📝Configuration

Client config

local tabletEntity = nil -- DO NOT CHANGE
local tabletModel = "pp_ems_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)
        SetModelAsNoLongerNeeded(tabletModel)
    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,

}

UI config

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

    announcements = {
        minContentLength = 30
    },

    bodyRegions = {
        { name = 'Head', x1 = 119, y1 = 5, x2 = 119 + 93, y2 = 5 + 93 },
        { name = 'Left Arm', x1 = 223, y1 = 117, x2 = 223 + 42, y2 = 117 + 128 },
        { name = 'Left Forearm', x1 = 230, y1 = 248, x2 = 230 + 93, y2 = 248 + 159 },
        { name = 'Right Arm', x1 = 54, y1 = 116, x2 = 54 + 52, y2 = 116 + 130 },
        { name = 'Right Forearm', x1 = 0, y1 = 248, x2 = 0 + 96, y2 = 248 + 155 },
        { name = 'Left Foot', x1 = 164, y1 = 635, x2 = 164 + 47, y2 = 635 + 55 },
        { name = 'Right Foot', x1 = 111, y1 = 635, x2 = 111 + 44, y2 = 635 + 58 },
        { name = 'Right Calf', x1 = 95, y1 = 491, x2 = 95 + 61, y2 = 491 + 140 },
        { name = 'Left Calf', x1 = 164, y1 = 494, x2 = 164 + 57, y2 = 494 + 135 },
        { name = 'Left Thigh', x1 = 156, y1 = 318, x2 = 156 + 64, y2 = 318 + 176 },
        { name = 'Right Thigh', x1 = 96, y1 = 316, x2 = 96 + 56, y2 = 316 + 172 },
        { name = 'Chest', x1 = 101, y1 = 109, x2 = 101 + 113, y2 = 109 + 204 },
    },

    playerPositionRefreshRate = 1000, -- time in milliseconds which indicates how often the player's position on the map should be updated

    patrols = {
        statusTypes = {"Patrol", "Break", "Own Intervention", "Responding", "Other", "Transporting a patient"},
        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 patient'] = "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

local Framework = nil

if GetResourceState('es_extended') ~= 'missing' then
    Framework = 'ESX'
    ESX = exports.es_extended:getSharedObject()
elseif GetResourceState('qbx_core') ~= 'missing' then
    Framework = 'QBOX'
elseif GetResourceState('qb-core') ~= 'missing' then
    Framework = 'QBCore'
    QBCore = exports['qb-core']:GetCoreObject()
elseif GetResourceState('your_custom_framework') ~= 'missing' then -- fill it when you are using other framework
    Framework = 'your_custom_framework'
end

return {
    debug = true, -- debug mode, do not use in production !!!
    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 = {
        'ambulance'
    },

    homePage = {
        getDoctorData = function(player)
            local radiochannel, image, badge = nil, nil, nil
            if Framework == 'ESX' then
                radiochannel = Player(player.source).state.radioChannel
                image = player.getMeta('ems_mdt_image')
                badge = player.getMeta('badge') or 0
            elseif Framework == 'QBCore' or Framework == 'QBOX' then
                radiochannel = Player(player.PlayerData.source).state.radioChannel
                image = player.PlayerData.metadata.ems_mdt_image
                badge = player.PlayerData.metadata.callsign or 0
            end

            return {
                radio = radiochannel,
                img = image,
                badge = badge
            }
        end,
        getPhoto = function(identifier)
            local image = nil
            if Framework == 'ESX' then
                local player = ESX.GetPlayerFromIdentifier(identifier)

                if player then
                    image = player.getMeta('ems_mdt_image')
                else
                    local response = MySQL.query.await("SELECT JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.ems_mdt_image')) AS ems_mdt_image, FROM `users` WHERE `identifier` = ?", {
                        identifier
                    })
                    if response and response[1] then
                        image = response[1].ems_mdt_image
                    end
                end
            elseif Framework == 'QBOX' then
                local player = exports.qbx_core:GetPlayerByCitizenId(identifier) or exports.qbx_core:GetOfflinePlayer(identifier)
                image = player?.PlayerData.metadata.ems_mdt_image
            elseif Framework == 'QBCore' then
                local player = QBCore.Functions.GetPlayerByCitizenId(identifier) or QBCore.Functions.GetOfflinePlayerByCitizenId(identifier)
                image = player?.PlayerData.metadata.ems_mdt_image
            end

            return image
        end
    },

    citizen = {
        updatePhoto = function(identifier, url)
            if Framework == 'ESX' then
                local player = ESX.GetPlayerFromIdentifier(identifier)
                if player then
                    player.setMeta('ems_mdt_image', url)
                else
                    MySQL.update.await("UPDATE `users` SET `metadata` = JSON_SET(`metadata`, '$.ems_mdt_image', ?) WHERE `identifier` = ?", {
                        url,
                        identifier
                    })
                end
            elseif Framework == 'QBOX' then
                local player = exports.qbx_core:GetPlayerByCitizenId(identifier) or exports.qbx_core:GetOfflinePlayer(identifier)
                if not player then return false end

                player.Functions.SetMetaData('ems_mdt_image', url)
            elseif Framework == 'QBCore' then
                local player = QBCore.Functions.GetPlayerByCitizenId(identifier) or QBCore.Functions.GetOfflinePlayerByCitizenId(identifier)
                if not player then return false end
    
                player.Functions.SetMetaData('ems_mdt_image', url)
            end
            return true
        end,
        getCitizenDetails = function(identifier)
            local response = {}

            if Framework == 'ESX' then
                local data = {}
                local player = ESX.GetPlayerFromIdentifier(identifier)

                if player then
                    data.firstname = player.get('firstName')
                    data.lastname = player.get('lastName')
                    data.birthdate = player.get('dob')
                    data.nationality = player.get('nationality')
                    data.ems_mdt_image = player.getMeta('ems_mdt_image')
                    data.badge = player.getMeta('badge')
                else
                    local response = MySQL.query.await("SELECT `firstname`, `lastName`, `dateofbirth` AS `dob`, `nationality`, JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.ems_mdt_image')) AS ems_mdt_image, JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.badge')) AS badge FROM `users` WHERE `identifier` = ?", {
                        identifier
                    })
                    if response and response[1] then
                        data.firstname = response[1].firstname
                        data.lastname = response[1].lastName
                        data.birthdate = response[1].dob
                        data.nationality = response[1].nationality
                        data.ems_mdt_image = response[1].ems_mdt_image
                        data.badge = response[1].badge
                    end
                end

                response = {
                    name = data.firstname .. ' ' .. data.lastname,
                    dob = data.birthdate,
                    img = data.ems_mdt_image,
                    ssn = identifier,
                    nationality = data.nationality,
                    badge = data.badge
                }
            elseif Framework == 'QBOX' then
                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

                response = {
                    name = data.charinfo.firstname .. ' ' .. data.charinfo.lastname,
                    dob = data.charinfo.birthdate,
                    img = data.metadata.ems_mdt_image,
                    ssn = identifier,
                    nationality = data.charinfo.nationality,
                    licenses = licenses
                }
            elseif Framework == 'QBCore' then
                local player = QBCore.Functions.GetPlayerByCitizenId(identifier) or QBCore.Functions.GetOfflinePlayerByCitizenId(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
    
                response = {
                    name = data.charinfo.firstname .. ' ' .. data.charinfo.lastname,
                    dob = data.charinfo.birthdate,
                    img = data.metadata.ems_mdt_image,
                    ssn = identifier,
                    nationality = data.charinfo.nationality,
                    licenses = licenses
                }
            end


            return response
        end
    },

    case = {
        giveInvoice = function(identifier, fine, data)
            -- fill with your own ticket system
        end,
        injuries = {
            {
                name = 'First-degree burn', -- Oparzenie 1. stopnia
                price = 1000
            },
            {
                name = 'Second-degree burn', -- Oparzenie 2. stopnia
                price = 1500
            },
            {
                name = 'Third-degree burn', -- Oparzenie 3. stopnia
                price = 2500
            },
            {
                name = 'Open fracture', -- Złamanie otwarte
                price = 2000
            },
            {
                name = 'Closed fracture', -- Złamanie zamknięte
                price = 1500
            },
            {
                name = 'Concussion', -- Wstrząs mózgu
                price = 1200,
                onlyForRegion = 'Head'
            },
            {
                name = 'Hematoma', -- Krwiak
                price = 800
            },
            {
                name = 'Dislocation', -- Zwichnięcie
                price = 1100
            },
            {
                name = 'Sprain', -- Skręcenie
                price = 900
            },
            {
                name = 'Minor laceration', -- Małe rozcięcie
                price = 700
            },
            {
                name = 'Deep laceration', -- Głębokie rozcięcie
                price = 1600
            },
            {
                name = 'Whiplash injury', -- Uraz kręgosłupa szyjnego
                price = 1300,
                onlyForRegion = 'Head'
            },
            {
                name = 'Puncture wound', -- Rana kłuta
                price = 1700
            },
            {
                name = 'Gunshot wound', -- Rana postrzałowa
                price = 3000
            },
        }
    },

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

    dispatch = {
        getGender = function(frPlayer)
            local gender = nil
            if Framework == 'ESX' then
                gender = frPlayer.get('sex') == 'm' and "Male" or "Female"
            elseif Framework == 'QBOX' then
                gender = frPlayer.PlayerData.charinfo.gender and "Male" or "Female"
            end
            return gender
        end,
    },

    permissions = {
        [1] = { -- [grade] = { permissions }
            announcements = {
                'view',
            },
            patrols = {
                'view',
            },
            citizens = {
                'view'
            },
            citizen = {
                'view',
            },
            cases = {
                'view',
            },
            case = {
                'view',
            },
            notes = {
                'view',
            },
            note = {
                'view',
            },
            settings = {
                'view'
            }
        },
        [2] = {
            homepage = {
                'chat',
                'search'
            },
            announcements = {
                'create',
            },
            announcement = {
                'edit',
                'remove'
            },
            patrols = {
                'create'
            },
            citizen = {
                'photo',
                'viewcases',
                'viewnotes',
                'viewvehicles'
            },
            cases = {
                'listview',
                'create'
            },
            case = {
                'edit'
            },
            notes = {
                'listview',
                'create'
            },
            note = {
                'edit',
                'remove'
            }
        }
    },

    queries = (Framework == 'QBOX' or Framework == 'QBCore') and {
        ['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, '$.ems_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
        ]],
        ['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 (?)
        ]],
        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]],
            ['doctors'] = [[
                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')) IN (@jobs)
                    AND (
                        JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.firstname')) LIKE @query
                        OR JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.lastname')) LIKE @query
                    )
                LIMIT 20;
            ]],
        }
    } or {
        ['searchCitizens'] = [[
            SELECT
                COUNT(*) as count
            FROM
                users
            WHERE
                firstname LIKE @search
                OR lastname LIKE @search
        ]],
        ['getCitizens'] = [[
            SELECT
                identifier AS identifier,
                identifier AS ssn,
                firstname,
                lastname,
                JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.ems_mdt_image')) AS image
            FROM
                users
            WHERE
                firstname LIKE @search
                OR lastname LIKE @search
            LIMIT @limit OFFSET @offset
        ]],
        ['getAuthor'] = [[
            SELECT
                firstname,
                lastname
            FROM
                users
            WHERE
                identifier = ?
        ]],
        ['getCitizensByIdentifiers'] = [[
            SELECT
                identifier AS identifier,
                firstname,
                lastname
            FROM
                users
            WHERE
                identifier IN (?)
        ]],
        search = {
            ['citizens'] = [[
                SELECT
                    identifier AS identifier,
                    firstname,
                    lastname
                FROM
                    users
                WHERE
                    firstname LIKE @query
                    OR lastname LIKE @query
                LIMIT 20
            ]],
            ['doctors'] = [[
                SELECT `identifier`, `lastname`, `firstname`
                FROM `users`
                WHERE `job` IN (@jobs)
                AND (firstname LIKE @query OR lastname LIKE @query)
                LIMIT 20;
            ]],
        }
    }
}

Last updated