# Configuration

{% code title="config.lua" %}

```lua
Config = {Locales = {}}

Config.Framework = 'auto' -- 'auto', 'qb' (use qb for qbox), 'esx', 'custom' -- setup custom in bridges/custom/custom_bridge.lua

--[[
    Only required if Config.Framework = 'esx'
    Options:
        'new' -- v1.8.5-latest
        'old' -- v1 - v.1.8.5
]]
Config.ESXVersion = 'new'

Config.Phone = 'auto' -- options: 'auto', 'qb-phone', 'qbx_npwd' 'quasar', 'gksphone', 'lbphone', 'yflip', 'okokPhone', 'jpr-phonesystem', 'roadphone', 'custom' -- for mail -- setup custom in config/sv_customizable_functions.lua

Config.Interface = {
    Menu = 'ox', -- options 'qb', 'ox', 'custom' -- editable in cl_customizable_functions.lua
    Input = 'ox', -- options 'qb', 'ox', 'custom' -- editable in cl_customizable_functions.lua
    Notifications = 'ox', -- options 'esx', 'qb', 'ox', 'custom' -- editable in cl_customizable_functions.lua
    TextUI = 'ox' -- options 'esx', 'qb', 'ox', 'custom' -- editable in cl_customizable_functions.lua
}

Config.Zones = 'ox' -- options 'PolyZone', 'ox', 'custom' -- editable in cl_customizable_functions.lua

Config.Target = false  -- true/false

Config.DeputyVoting = { -- additional setting for deputy voting to allow or prohibit president and chairman from vote on deputy votes
    president = true, -- true if you want to allow the president to vote in deputies votings, false if you don't want to.
    chairman = true -- true if you want to allow the chairman to vote in deputies votings, false if you don't want to.
}

Config.Translation = 'en' -- check in 'locales' folder

Config.TaxSystem = 1 -- option 1 = tax not included in price, option 2 = tax included in price || example for 20% tax: (1 = player will pay 12$ for 10$ product) (2 = player will pay 10$ for 10$ product but shop recieves 8$)

Config.PartyManagement = { -- commands for the politcal parties
    manageParty = "managepp",
    checkMyParty = "pp",
    leaveParty = "leavepp"
}

Config.LawsCommand = { -- command and keybind for opening the laws menu. Keybind can be changed in-game from the FiveM options menu!
    commandName = 'laws',
    keyBind = 'B',
}

Config.Blips = {
    townhall = {
        show = true,
        sprite = 525, -- https://docs.fivem.net/docs/game-references/blips/
        color = 0, -- https://docs.fivem.net/docs/game-references/blips/
        size = 0.8, -- has to be in decimals
        label = 'Town Hall',
        coords = vector3(-556.03, -193.58, 38.23)
    }
}

Config.Icons = { -- check compatible icons depending on what interface (menu/input) you use - default https://fontawesome.com (compatible with ox/qb)
    ['Manage Members'] = 'fas fa-users',
    ['Create Election'] = 'fas fa-users',
    ['End Election'] = 'fas fa-vote-yea',
    ['Ban From Elections'] = 'fas fa-ban',
    ['Unban From Elections'] = 'fas fa-check-square',
    ['Clear Player Votes'] = 'fas fa-eraser',
    ['Announcement'] = 'fas fa-paper-plane',
    ['Hire Deputy'] = 'fas fa-briefcase',
    ['Fire Deputy'] = 'fas fa-sign-out-alt',
    ['Money Management'] = 'fas fa-university',
    ['Money Deposit'] = 'fas fa-donate',
    ['Money Withdraw'] = 'fas fa-money-bill-wave',
    ['Election Options'] = 'fas fa-print',
    ['Political Parties Options'] = 'fas fa-user-slash',
    ['Other Options'] = 'fas fa-paper-plane',
    ['President Menu'] = 'fas fa-flag',
    ['Conference Menu'] = 'fas fa-book-open',
    ['Conference Menu Title'] = 'fas fa-bookmark',
    ['Party Application'] = 'fas fa-book-open',
    ['Party Application Title'] = 'fas fa-bookmark',
    ['Party Applications List'] = 'fas fa-print',
    ['Voting Menu'] = 'fas fa-print',
    ['Party Rename'] = 'fas fa-pen',
    ['Party Disband'] = 'fas fa-trash',
    ['Manage Political Parties'] = 'fas fa-list',
    ['Tax Management'] = 'fas fa-money-bill',
    ['Income Tax'] = 'fas fa-percent',
    ['VAT Tax'] = 'fas fa-percent'
}

Config.Job = {
    jobname = 'politician',
    joblabel = 'Politician',
    grades = { --- do not change keys (president, chairman, deputy), only change numbers of grades (if wanted), and keep the order of numbers from lower perms to higher perms
        president = 2,
        chairman = 1,
        deputy = 0
    }
}

Config.PresidentMenu = {
    targetCoords = vector3(-528.66, -188.68, 42.95),
    pedHeading = 121.93,
}

Config.ConferenceRoom = {
    targetCoords = vector3(-534.69, -178.28, 43.80), -- location of the conference menu
    roomCoords = vector3(-537.2, -179.84, 44.26), -- put the center of the room
    radius = 15, -- the radius from the room coords where deputies can vote ( we don't want someone who is not in the hall to vote so that's why we are using this )
}

Config.Application = {
    ped = {
        pedModel = 'cs_bankman',
        pedCoords = vector3(-542.43, -197.23, 38.24),
        pedHeading = 77.25,
    },
}

Config.VotingLocation = {
    {
        points = { -- acts as points for polyzone/qb-target/ox_target/ox_lib
            vector3(-541.32, -183.47, 37.23),
            vector3(-543.91, -179.28, 37.23),
            vector3(-542.76, -178.18, 37.23),
            vector3(-540.39, -182.63, 37.23)
        },
        label = 'Vote'
    },
    {
        points = { -- acts as points for polyzone/qb-target/ox_target/ox_lib
            vector3(-535.76, -174.53, 37.23),
            vector3(-533.43, -178.4, 37.23),
            vector3(-534.19, -173.66, 37.23),
            vector3(-531.93, -177.52, 37.23)
        },
        label = 'Vote',
        coords = {
            vector3(-542.92, -179.23, 38.23),
            vector3(-542.11, -180.59, 38.23),
            vector3(-541.32, -181.97, 38.23)
        }
    }
}

function Translate(msg, ...)
    if Config.Locales[Config.Translation] then
        if Config.Locales[Config.Translation][msg] then
            return string.format(Config.Locales[Config.Translation][msg], ...)
        elseif Config.Translation ~= 'en' and Config.Locales['en'] and Config.Locales['en'][msg] then
            return string.format(Config.Locales['en'][msg], ...)
        else
            return 'Translation ['.. Config.Translation ..'] ['..msg..'] does not exist.'
        end
    elseif Config.Translation ~= 'en' and Config.Locales['en'] and Config.Locales['en'][msg] then
        return string.format(Config.Locales['en'][msg], ...)
    else
        return 'Translation ['.. Config.Translation .. '] not found.'
    end
end

local function detectFramework()
    if (GetResourceState('qb-core') == 'started') then return 'qb' end
    if (GetResourceState('qbox') == 'started') then return 'qb' end
    if (GetResourceState('es_extended') == 'started') then return 'esx' end
    return 'custom'
end

if Config.Framework == 'auto' then Config.Framework = detectFramework() end

local function detectPhone()
    if (GetResourceState('qb-phone') == 'started') then return 'qb-phone' end
    if (GetResourceState('qs-smartphone') == 'started') then return 'quasar' end
    if (GetResourceState('gksphone') == 'started') then return 'gksphone' end
    if (GetResourceState('lb-phone') == 'started') then return 'lbphone' end
    if (GetResourceState('yflip-phone') == 'started') then return 'yflip' end
    if (GetResourceState('okokPhone') == 'started') then return 'okokPhone' end
    if (GetResourceState('jpr-phonesystem') == 'started') then return 'jpr-phonesystem' end
    if (GetResourceState('roadphone') == 'started') then return 'roadphone' end
    if (GetResourceState('qbx_npwd') == 'started') then return 'qbx_npwd' end
    return 'custom'
end

if Config.Phone == 'auto' then Config.Phone = detectPhone() end
```

{% endcode %}

<details>

<summary>webhooks.lua</summary>

```lua
Webhooks = {}

Webhooks.Array = {
    civilian_voting = '',
    deputies_voting = ''
}

Webhooks.BotName = 'Mr. Politics'
Webhooks.Header = 'Political System'
Webhooks.ProfilePicture = 'https://cdn.discordapp.com/attachments/1204869666493829184/1214581454651138088/BK.png?ex=65f9a220&is=65e72d20&hm=614a763e06556de7b8912775e0f5f7b2b18c8d1d9079edb4e5dfb370e206ada9&'

--[[
    blue = 255,
    red = 16711680,
    green = 65280,
    white = 16777215,
    black = 0,
    orange = 16744192,
    yellow = 16776960,
    pink = 16761035,
    lightgreen = 65309,
]]
Webhooks.Color = '255'
```

</details>

<details>

<summary>cl_customizable_functions.lua</summary>

```lua
function Notification(msg, type, duration)
    if Config.Interface.Notifications == 'qb' then
        QBCore.Functions.Notify(msg, type, duration)
    elseif Config.Interface.Notifications == 'ox' then
        lib.notify({id = msg, title = Translate('notificationTitle'), description = msg, duration = duration, type = type})
    elseif Config.Interface.Notifications == 'esx' then
        ESX.ShowNotification(msg)
    elseif Config.Interface.Notifications == 'custom' then
        -- your custom function
    end
end

function ShowTextUi(msg)
    if Config.Interface.TextUI == 'qb' then
        exports['qb-core']:DrawText(msg, 'right')
    elseif Config.Interface.TextUI == 'ox' then
        lib.showTextUI(msg)
    elseif Config.Interface.TextUI == 'esx' then
        ESX.TextUI(msg)
    elseif Config.Interface.TextUI == 'custom' then
        -- your custom function
    end
end

function HideTextUi()
    if Config.Interface.TextUI == 'qb' then
        exports['qb-core']:HideText()
    elseif Config.Interface.TextUI == 'ox' then
        lib.hideTextUI()
    elseif Config.Interface.TextUI == 'esx' then
        ESX.HideUI()
    elseif Config.Interface.TextUI == 'custom' then
        -- your custom function
    end
end

function Menu(arg)
    if Config.Interface.Menu == 'qb' then
        return exports['qb-menu']:openMenu(arg)
    elseif Config.Interface.Menu == 'ox' then
        return oxlibMenuHandler(arg)
    elseif Config.Interface.Menu == 'custom' then
        -- your custom function
    end
end

function Input(arg)
    if Config.Interface.Input == 'qb' then
        return exports['qb-input']:ShowInput(arg)
    elseif Config.Interface.Input == 'ox' then
        return oxlibInputHandler(arg)
    elseif Config.Interface.Input == 'custom' then
        -- your custom function
    end
end

function AddCircleZone(name, coords, radius, options1, options2)
    return exports['qb-target']:AddCircleZone(name, coords, radius, options1, options2) --qb-target/ox_target
end

function AddTargetEntity(name, options)
    return exports['qb-target']:AddTargetEntity(name, options) --qb-target/ox_target
end

function AddPolyZone(name, coords, options1, options2)
    return exports['qb-target']:AddPolyZone(name, coords, options1, options2) --qb-target/ox_target
end

function RemoveZone(name)
    pcall(function()
        return exports['qb-target']:RemoveZone(name)
    end) -- qb-target/ox_target
end

function PolyZoneCreation(points, data, playerInsideHandler)
    if Config.Zones == 'PolyZone' then
        local zone = PolyZone:Create(points, data)
        zone:onPlayerInOut(playerInsideHandler)

    elseif Config.Zones == 'ox' then
        local pointsConverted = {}
        for i = 1, #points do
            pointsConverted[i] = vector3(points[i].x, points[i].y, data.minZ + 1)
        end
        lib.zones.poly({
            points = pointsConverted,
            thickness = 4,
            onEnter = function() playerInsideHandler(true) end,
            onExit = function() playerInsideHandler(false) end
        })

    elseif Config.Zones == 'custom' then
        -- your custom zones handler
    end
end

function CircleZoneCreation(coords, radius, data, playerInsideHandler)
    if Config.Zones == 'PolyZone' then
        local zone = CircleZone:Create(coords, radius, data)
        zone:onPlayerInOut(playerInsideHandler)

    elseif Config.Zones == 'ox' then
        lib.zones.sphere({
            coords = coords,
            radius = radius,
            onEnter = function() playerInsideHandler(true) end,
            onExit = function() playerInsideHandler(false) end
        })

    elseif Config.Zones == 'custom' then
        -- your custom zones handler
    end
end
```

</details>

<details>

<summary>sv_customizable_functions.lua</summary>

```lua
function SendEMail(target, title, message)
    if Config.Phone == 'qb-phone' then
        QBphoneEmail(target, title, message)

    elseif Config.Phone == 'quasar' then
        TriggerClientEvent('bk_politicalsystem:client:quasarIntegration', target, title, message)

    elseif Config.Phone == 'gksphone' then
        local mailData = {
            sender = Translate('president_mail'),
            image = '/html/static/img/icons/mail.png',
            subject = title,
            message = message
        }
        exports['gksphone']:SendNewMail(target, mailData)

    elseif Config.Phone == 'lbphone' then
        local phoneNumber = exports['lb-phone']:GetEquippedPhoneNumber(target)
        local email = exports['lb-phone']:GetEmailAddress(phoneNumber)
        exports['lb-phone']:SendMail({
            to = email,
            subject = Translate('president')..' - '..title,
            message = message
        })

    elseif Config.Phone == 'yflip' then
        exports['yflip-phone']:SendMail({
            title = title,
            sender = Translate('president_mail'),
            senderDisplayName = Translate('president'),
            content = message
        }, 'source', target)

    elseif Config.Phone == 'okokPhone' then
        local email = exports['okokPhone']:getEmailAddressFromSource(target)

        exports['okokPhone']:sendEmail({
			sender = Translate('president_mail'),
            recipients = {email},
            subject = Translate('president')..' - '..title,
            body = message,
        })

    elseif Config.Phone == 'jpr-phonesystem' then
        TriggerEvent('jpr-phonesystem:server:sendEmail', {
            subject = title,
            message = message,
            sender = Translate('president_mail'),
            event = {},
        }, target)

    elseif Config.Phone == 'roadphone' then
        local identifier = GetPlayerIdentifierByType(target, "license")
        if identifier then
            local data = {
                sender = Translate('president_mail'),
                subject = title,
                message = message
            }
            exports['roadphone']:sendMailOffline(identifier, data)
        end

    elseif Config.Phone == 'qbx_npwd' then
        local Player = QBCore.Functions.GetPlayer(target)
        if not Player then
            print('[BK][MAIL][NPWD] Player nil for source=', target)
            return
        end
        local cid = Player.PlayerData.citizenid
        TriggerEvent('qb-phone:server:sendNewMailToOffline', cid, {
            sender = Translate('president_mail'),
            subject = title,
            message = message
        })

    elseif Config.Phone == 'custom' then
        -- your custom function
    end
end

function SendDiscordMessage(webhook, title, fields, color)
    if not Webhooks.Array[webhook] then return end

    local webhook = Webhooks.Array[webhook]
    local data = {
        {
            ['title'] = title,
            ['color'] = color or Webhooks.Color,
            ['footer'] = {
                ['text'] = os.date()
            },
            ['fields'] = type(fields) == 'table' and fields or nil,
            ['description'] = type(fields) == 'string' and fields or nil,
            ['author'] = {
                ['name'] = Webhooks.Header,
                ['icon_url'] = Webhooks.ProfilePicture
            }
        }
    }

    PerformHttpRequest(webhook, nil, 'POST', json.encode({
        username = Webhooks.BotName,
        embeds = data
    }), {['Content-Type'] = 'application/json'})
end

```

</details>


---

# Agent Instructions: 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:

```
GET https://docs.bkscripts.com/scripts/bk_politicalsystem/configuration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
