# Configuration File

{% code lineNumbers="true" fullWidth="true" %}

```lua
Config = {}

Config.Locale = 'en'
Config.DrawDistance = 10
Config.InteractionDistance = 1.5
Config.TextUIOn = false
Config.UseFrameworkTextUI = true -- else use custom
Config.UseFrameworkNotifications = true -- else use custom
Config.UseTarget = 'ox-target' -- ox-target, qb-target, custom, ''
Config.PlayerUpdateInterval = 10000 -- in ms, interval that updates player's info (name, cash, bank)
Config.FuelAmount = 70
Config.TestDriveLength = 30 -- In Seconds
Config.TestDrivePlate = 'TEST_DRV'
Config.possibleLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Config.possibleNums = "0123456789"
Config.PlateLetters = 3
Config.PlateNumbers = 3
Config.PlateSpace = true

Config.WebhookURL = ""
function LogToDiscord(title, msg, hexColor)
    local data = {
        username = "Vehicleshop Logs",
        embeds = {
            {
                title = title,
                description = msg,
                color = hexColor or 16777215
            }
        }
    }
    PerformHttpRequest(Config.WebhookURL, function(err, responseText, headers)
    end, "POST", json.encode(data), {
        ["Content-Type"] = "application/json"
    })
end

Config.LogEvent = function(type, data)
    local title, message, color = '', '', 16777215
    if type == 'purchase' then
        title = 'Vehicle Purchased'
        message = string.format(
            '**Source:** %s\n**Name:** %s\n**Identifier:** %s\n**Shop:** %s\n**Payment:** %s\n**Price:** %s\n**Plate:** %s\n**Model:** %s\n**Type:** %s\n**Bank:** %s\n**Cash:** %s',
            tostring(data.source or '-'),
            tostring(data.name or '-'),
            tostring(data.identifier or '-'),
            data.shop or '-',
            tostring(data.paymentMethod or '-'),
            tostring(data.vehicle.modelPrice or '-'),
            tostring(data.vehicle.plate or '-'),
            tostring(data.vehicle.model or '-'),
            tostring(data.vehicle.vehicleType or '-'),
            tostring(data.bank or '-'),
            tostring(data.money or '-')
        )
        color = 3066993
    elseif type == 'testdrive' then
        title = 'Test Drive'
        message = string.format(
            '**Source:** %s\n**Name:** %s\n**Identifier:** %s\n**Shop:** %s\n**Plate:** %s\n**Model:** %s\n**Type:** %s\n**Bank:** %s\n**Cash:** %s',
            tostring(data.source or '-'),
            tostring(data.name or '-'),
            tostring(data.identifier or '-'),
            data.shop or '-',
            tostring(data.vehicle.plate or '-'),
            tostring(data.vehicle.model or '-'),
            tostring(data.vehicle.vehicleType or '-'),
            tostring(data.bank or '-'),
            tostring(data.money or '-')
        )
        color = 3447003
    elseif type == 'failed_purchase' then
        title = 'Failed Purchase'
        message = string.format(
            '**Source:** %s\n**Name:** %s\n**Identifier:** %s\n**Shop:** %s\n**Payment:** %s\n**Price:** %s\n**Plate:** %s\n**Model:** %s\n**Type:** %s\n**Bank:** %s\n**Cash:** %s',
            tostring(data.source or '-'),
            tostring(data.name or '-'),
            tostring(data.identifier or '-'),
            data.shop or '-',
            tostring(data.paymentMethod or '-'),
            tostring(data.vehicle.modelPrice or '-'),
            tostring(data.vehicle.plate or '-'),
            tostring(data.vehicle.model or '-'),
            tostring(data.vehicle.vehicleType or '-'),
            tostring(data.bank or '-'),
            tostring(data.money or '-')
        )
        color = 15158332
    elseif type == 'license_purchase' then
        title = 'License Purchased'
        message = string.format(
            '**Source:** %s\n**Name:** %s\n**Identifier:** %s\n**License Name:** %s\n**License Price:** %s\n**Bank:** %s\n**Cash:** %s',
            tostring(data.source or '-'),
            tostring(data.name or '-'),
            tostring(data.identifier or '-'),
            tostring(data.license.label or '-'),  
            tostring(data.license.cost or '-'),  
            tostring(data.bank or '-'),
            tostring(data.money or '-')
        )
        color = 15844367
    elseif type == 'failed_license_purchase' then
        title = 'Failed License Purchase'
        message = string.format(
            '**Source:** %s\n**Name:** %s\n**Identifier:** %s\n**License Name:** %s\n**License Price:** %s\n**Bank:** %s\n**Cash:** %s',
            tostring(data.source or '-'),
            tostring(data.name or '-'),
            tostring(data.identifier or '-'),
            tostring(data.license.label or '-'),  
            tostring(data.license.cost or '-'),  
            tostring(data.bank or '-'),
            tostring(data.money or '-')
        )
        color = 15158332
    elseif type == 'open_shop' then
        title = 'Shop Opened'
        message = string.format(
            '**Source:** %s\n**Name:** %s\n**Identifier:** %s\n**Shop:** %s',
            tostring(data.source or '-'),
            tostring(data.name or '-'),
            tostring(data.identifier or '-'),
            data.shop or '-'
        )
        color = 3066993
    elseif type == 'open_license_shop' then
        title = 'License Shop Opened'
        message = string.format(
            '**Source:** %s\n**Name:** %s\n**Identifier:** %s\n**License Shop:** %s',
            tostring(data.source or '-'),
            tostring(data.name or '-'),
            tostring(data.identifier or '-'),
            data.licenseshop or '-'
        )
        color = 3066993
    elseif type == 'close_shop' then
        title = 'Shop Closed'
        message = string.format(
            '**Source:** %s\n**Name:** %s\n**Identifier:** %s',
            tostring(data.source or '-'),
            tostring(data.name or '-'),
            tostring(data.identifier or '-')
        )
        color = 15105570
    elseif type == 'close_license_shop' then
        title = 'License Shop Closed'
        message = string.format(
            '**Source:** %s\n**Name:** %s\n**Identifier:** %s',
            tostring(data.source or '-'),
            tostring(data.name or '-'),
            tostring(data.identifier or '-')
        )
        color = 15105570
    else
        title = 'Unknown Event'
        message = json.encode(data)
    end
    LogToDiscord(title, message, color)
end

Config.VehicleShops = {
    ['PDM'] = {
        label = 'PDM',
        requireslicense = true, -- if using esx then it requires esx_license
        license = 'drive',
        defaultgarage = 'pillboxgarage', -- set it to your own garage
        cantestdrive = true,
        entry_coords = vector3(-57.0261, -1097.2019, 26.4223),
        inside_coords = vector4(-45.7, -1097.0, 25.4, 12),
        testdrive_coords = vector4(-1653.353, -2763.669, 13.94467, 233.3984),
        outside_coords = {
            [0] = vector4(-56.3973, -1116.9412, 25.8094, 2.6969),
            [1] = vector4(-53.5938, -1116.8580, 25.8096, 1.9333),
            [2] = vector4(-50.6819, -1116.7091, 25.8097, 2.2443),
            [3] = vector4(-47.7587, -1116.5823, 25.8090, 2.6434),
            [4] = vector4(-45.0273, -1116.5021, 25.8090, 3.1171),
            [5] = vector4(-31.7978, -1091.0040, 25.7976, 331.1530)
        },

        target = {
            usetarget = false,
            pedposition = vector4(-56.9267, -1098.7959, 25.4224, 27.8733),
            pedmodel = 'cs_bankman'
        },

        marker = {
            show = false, -- if usetarget is true then this will not work
            display = 36,
            scale = 0.8,
            color = vector4(5, 155, 155, 200),
            upAndDown = true,
            faceCamera = false,
            rotation = vector3(0, 0, 27.8)
        },

        draw3dtext = {
            show = false, -- if usetarget is true then this will not work
            textColor = vector4(222, 222, 222, 200)
        },

        blip = {
            show = true,
            display = 4,
            sprite = 326,
            scale = 0.8,
            color = 26,
            blip_coords = vector3(-57.0261, -1097.2019, 26.4223)
            -- https://docs.fivem.net/docs/game-references/blips/
        }

    },

    ['BoatShop'] = {
        label = 'Boat Shop',
        requireslicense = false, -- if using esx then it requires esx_license
        cantestdrive = true,
        license = 'boat',
        defaultgarage = 'pillboxgarage', -- set it to your own garage
        entry_coords = vector3(-719.4128, -1326.066, 1.59629),
        inside_coords = vector4(-713.3442, -1341.499, 0.0037106, 138.0586),
        testdrive_coords = vector4(-713.3442, -1341.499, 0.1737106, 138.4586),
        outside_coords = {
            [0] = vector4(-714.3521, -1341.258, 1.596288, 139.8942),
            [1] = vector4(-733.6661, -1362.779, 1.596288, 138.7533),
            [2] = vector4(-727.1772, -1337.203, 1.596288, 230.5091),
            [3] = vector4(-733.1439, -1344.113, 1.596288, 232.1902)
        },

        target = {
            usetarget = true,
            pedposition = vector4(-718.5071, -1326.7778, 0.5993, 49.0270),
            pedmodel = 'cs_drfriedlander'
        },

        marker = {
            show = true, -- if usetarget is true then this will not work
            display = 35,
            scale = 0.8,
            color = vector4(25, 155, 155, 200),
            upAndDown = true,
            faceCamera = false,
            rotation = vector3(0, 0, 50)
        },

        draw3dtext = {
            show = false, -- if usetarget is true then this will not work
            textColor = vector4(222, 222, 222, 200)
        },

        blip = {
            show = true, 
            display = 4,
            sprite = 427,
            scale = 0.8,
            color = 26,
            blip_coords = vector3(-719.4128, -1326.066, 1.59629)
            -- https://docs.fivem.net/docs/game-references/blips/
        }

    },

    ['AircraftShop'] = {
        label = 'Aircraft Shop',
        requireslicense = true, -- if using esx then it requires esx_license
        license = 'jet',
        cantestdrive = false,
        defaultgarage = 'pillboxgarage', -- set it to your own garage
        entry_coords = vector3(-986.3480, -2954.3804, 13.9451),
        inside_coords = vector4(-984.1301, -2993.3569, 13.9451, 58.3566),
        testdrive_coords = vector4(-984.1301, -2993.3569, 13.9451, 58.3566),
        outside_coords = {
            [0] = vector4(-984.1301, -2993.3569, 13.9451, 58.3566),
            [1] = vector4(-963.9906, -2971.3303, 13.9451, 99.5131)
        },

        target = {
            usetarget = true, 
            pedposition = vector4(-985.4175, -2953.757, 12.94, 120),
            pedmodel = 'cs_josh'
        },

        marker = {
            show = true, -- if usetarget is true then this will not work
            display = 33,
            scale = 0.8,
            color = vector4(5, 155, 155, 200),
            upAndDown = true,
            faceCamera = false,
            rotation = vector3(0, 0, 124)
        },

        draw3dtext = {
            show = false, -- if usetarget is true then this will not work
            textColor = vector4(222, 222, 222, 200)
        },

        blip = {
            show = true,
            display = 4,
            sprite = 307,
            scale = 0.8,
            color = 26,
            blip_coords = vector3(-984.1301, -2993.3569, 13.9451)
            -- https://docs.fivem.net/docs/game-references/blips/
        }

    },
    ['PoliceShop'] = {
        label = 'Police Shop',
        requireslicense = true, -- if using esx then it requires esx_license
        license = 'drive',
        defaultgarage = 'pillboxgarage', -- set it to your own garage
        cantestdrive = false,
        job = 'police',
        entry_coords = vector3(451.8831, -1026.8040, 28.5493),
        inside_coords = vector4(449.7116, -1018.9793, 28.5066, 96.1280),
        testdrive_coords = vector4(-1653.353, -2763.669, 13.94467, 233.3984),

        outside_coords = {
            [0] = vector4(449.7116, -1018.9793, 28.5066, 96.1280),
            [1] = vector4(446.2233, -1024.8286, 28.2203, 2.4020),
            [2] = vector4(442.3069, -1025.4528, 28.2997, 5.2887),
            [3] = vector4(434.6925, -1026.4427, 28.4529, 7.0162)
        },

        target = {
            usetarget = true,
            pedposition = vector4(451.8831, -1027.6040, 27.5493, 11.4564),
            pedmodel = 's_m_y_cop_01'
        },

        marker = {
            show = true, -- if usetarget is true then this will not work
            display = 36,
            scale = 0.8,
            color = vector4(5, 155, 155, 200),
            upAndDown = true,
            faceCamera = false,
            rotation = vector3(0, 0, 8)
        },

        draw3dtext = {
            show = false, -- if usetarget is true then this will not work
            textColor = vector4(222, 222, 222, 111)
        },

        blip = {
            show = false,
            display = 4,
            sprite = 326,
            scale = 0.8,
            color = 26,
            blip_coords = vector3(451.8831, -1026.8040, 28.5493)
            -- https://docs.fivem.net/docs/game-references/blips/
        }

    },
    ['AmbulanceShop'] = {
        label = 'Ambulance Shop',
        requireslicense = true, -- if using esx then it requires esx_license
        license = 'drive',
        defaultgarage = 'pillboxgarage', -- set it to your own garage
        cantestdrive = false,
        job = 'ambulance',
        entry_coords = vector3(296.9276, -605.2386, 43.317),
        inside_coords = vector4(292.4497, -610.5320, 43.3769, 68.2980),
        testdrive_coords = vector4(-1653.353, -2763.669, 13.94467, 233.3984),
        outside_coords = {
            [0] = vector4(292.4497, -610.5320, 43.3769, 68.2980),
            [1] = vector4(294.1190, -589.3290, 42.8956, 337.5398)
        },

        target = {
            usetarget = true,
            pedposition = vector4(296.9276, -606.2386, 42.3175, 166.5154),
            pedmodel = 'mp_m_securoguard_01'
        },

        marker = {
            show = true, -- if usetarget is true then this will not work
            display = 36,
            scale = 0.8,
            color = vector4(5, 155, 155, 200),
            upAndDown = true,
            faceCamera = false,
            rotation = vector3(0, 0, 166)
        },

        draw3dtext = {
            show = false, -- if usetarget is true then this will not work
            textColor = vector4(222, 222, 222, 111)
        },

        blip = {
            show = false,
            display = 4,
            sprite = 326,
            scale = 0.8,
            color = 26,
            blip_coords = vector3(296.9276, -605.2386, 43.3175)
            -- https://docs.fivem.net/docs/game-references/blips/
        }

    },
}

Config.UseLicenseShop = true

Config.LicenseShop = {
    label = 'License Shop',
    entry_coords = vector3(223.8386, -1394.9097, 30.5875),
    licenses = {{
        name = 'boat',
        label = 'Boat License',
        cost = 90000
    }, {
        name = 'drive',
        label = 'Vehicle License',
        cost = 35000
    }, {
        name = 'jet',
        label = 'Pilot License',
        cost = 235000
    } 
    },

    target = {
        usetarget = true,
        pedposition = vector4(223.8386, -1394.9097, 29.5575, 278.6431),
        pedmodel = 'cs_josh'
    },

    marker = {
        show = true, -- if usetarget is true then this will not work
        display = 21,
        scale = 0.8,
        color = vector4(155, 255, 155, 200),
        upAndDown = true,
        faceCamera = false,
        rotation = vector3(0, 0, 278.6431)
    },

    draw3dtext = {
        show = false, -- if usetarget is true then this will not work
        textColor = vector4(222, 222, 222, 111)
    },

    blip = {
        show = true,
        display = 4,
        sprite = 764,
        scale = 0.8,
        color = 26,
        blip_coords = vector3(223.8386, -1394.9097, 30.5875)
        -- https://docs.fivem.net/docs/game-references/blips/
    }
}

Config.ShowTextUI = function(text)
    -- @param {string} text The message to be displayed in the TextUi
    if Config.TextUIOn then
        if Config.UseFrameworkTextUI then
            if FrameworkName == 'es_extended' then
                ESX.TextUI(text)
            elseif FrameworkName == 'qb-core' then
                exports['qb-core']:DrawText(text, 'right')
            end
        else
            -- Custom
            lib.showTextUI(text) --uncomment '@ox_lib/init.lua' in fxmanifest.lua to use it
        end
    end
end

Config.HideTextUI = function()
    if Config.TextUIOn then
        if Config.UseFrameworkTextUI then
            if FrameworkName == 'es_extended' then
                ESX.HideUI()
            elseif FrameworkName == 'qb-core' then
                exports['qb-core']:HideText()
            end
        else
            -- Custom
            lib.hideTextUI() --uncomment '@ox_lib/init.lua' in fxmanifest.lua to use it
        end
    end
end

Config.Notify = function(text, type)
    -- @param {string} text The message to be displayed in the notification
    -- @param {string} type The type of notification. Can be "success", "info", or "error"
    if Config.UseFrameworkNotifications then
        if FrameworkName == 'es_extended' then
            ESX.ShowNotification(text, type, 1200)
        elseif FrameworkName == 'qb-core' then
            QBCore.Functions.Notify(text, type, 1200)
        end
    else
        -- Custom
        lib.notify({title = text,  position = 'bottom-right', description = 'Notification description', type = type})
    end
    
end

Config.InsertIntoDatabase = function(veh_data)
    if FrameworkName == 'es_extended' then
    -- This code is used to insert a vehicle into the database while using ESX        
        MySQL.insert('INSERT INTO owned_vehicles (owner, plate, vehicle, type, job, garage) VALUES (?, ?, ?, ?, ?, ?)', {
            xPlayer.identifier,
            veh_data.plate,
            json.encode(veh_data.vehicleProperties),
            veh_data.vehicleType,
            veh_data.job,
            veh_data.garage
        })
    elseif FrameworkName == 'qb-core' then
    -- This code is used to insert a vehicle into the database while using QBCORE
        MySQL.insert('INSERT INTO player_vehicles (license, citizenid, vehicle, hash, mods, plate, job, garage, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)', {
            xPlayer.PlayerData.license,
            xPlayer.PlayerData.citizenid,
            veh_data.model,
            GetHashKey(veh_data.model),
            json.encode(veh_data.vehicleProperties),
            veh_data.plate,
            veh_data.job,
            veh_data.garage,
            0
        })
    end
end

Config.SetFuel = function(vehicle, amount)
    -- @param {number} amount The amount of fuel
    amount = math.clamp(amount, 0, 100)
    -- exports["LegacyFuel"]:SetFuel(vehicle, amount) -- LegacyFuel
    -- Entity(vehicle).state.fuel = amount -- ox_fuel
    SetVehicleFuelLevel(vehicle, amount) -- none, may not work 

end

Config.SetCarkeys = function(plate, source)
    TriggerClientEvent('vehiclekeys:client:SetOwner',source, plate) -- for qbcore, default script, change it to your script, if you dont use any carlock script leave it blank
end

Config.GetCurrentVehicleType = function(vehicle)
    local type = GetVehicleType(vehicle)
    if type == 'automobile' or type == 'bike' then
        type = 'car'
    elseif type == 'submarine' then
        type = 'boat'
    elseif type == 'heli' or type == 'plane' then
        type = 'jet'
    end
    return type
end


Config.TargetPed = function(_, shop, action, ped)
    CreateThread(function()
        function GetLocale()
            local label
            if action == 'vehicleshop' then
                label = Translate('open')
            end
            if action == 'licenseshop' then
                label = Translate('open_licenseShop')
            end
            return label
        end
        
        if Config.UseTarget == 'qb-target' then
            -- Using QB-TARGET
            exports['qb-target']:AddTargetEntity(ped, {
                options = {{
                    num = 1,
                    icon = 'fas fa-example',
                    label = GetLocale(),
                    targeticon = 'fas fa-example',
                    action = function(ped)
                        if IsPedAPlayer(ped) then
                            return false
                        end
                        if action == 'vehicleshop' then
                            DoesRequireLicense(_, shop)
                        end
                        if action == 'licenseshop' then
                            ShowLicenseMenu()
                        end

                    end

                }},
                distance = Config.InteractionDistance
            })
        elseif Config.UseTarget == 'ox-target' then
            -- Using OX-TARGET
            
            local options = {{
                name = 'ox:option1',
                onSelect = function(data, ped)
                    if IsPedAPlayer(ped) then
                        return false
                    end
                    if action == 'vehicleshop' then
                        DoesRequireLicense(_, shop)
                    end
                    if action == 'licenseshop' then
                        label = Translate('open_licenseShop')
                        ShowLicenseMenu()
                    end

                end,
                distance = Config.InteractionDistance,
                icon = 'fa-solid fa-road',
                label = GetLocale()
            }}

            local optionNames = {'ox:option1'}
            exports.ox_target:addLocalEntity(ped, options)
        elseif Config.UseTarget == 'custom' then
            -- Custom
        end
    end)

end

```

{% endcode %}

{% code lineNumbers="true" fullWidth="true" %}

```lua
```

{% endcode %}


---

# 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://fjsf-scripts.gitbook.io/fjsf-scripts-docs/scripts/fjsf_vehicleshop/configuration-file.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.
