> For the complete documentation index, see [llms.txt](https://tcdev.gitbook.io/tcd-documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tcdev.gitbook.io/tcd-documentation/free-release/advanced-starterpack-system/configurations.md).

# Configurations

Advanced Starterpack Configurations

{% tabs %}
{% tab title="config.lua" %}

```lua
Config = {}

--[[
▀█▀ █▀▀ █▀▀ ▀█ █▄█   █▀▀ █▀█ █▀█ █▀▀   █▀▄ █▀▀ █░█ █▀▀ █░░ █▀█ █▀█ █▀▄▀█ █▀▀ █▄░█ ▀█▀
░█░ ██▄ ██▄ █▄ ░█░   █▄▄ █▄█ █▀▄ ██▄   █▄▀ ██▄ ▀▄▀ ██▄ █▄▄ █▄█ █▀▀ █░▀░█ ██▄ █░▀█ ░█░

    Documentation: https://tcdev.gitbook.io/tcd-documentation/free-release/advanced-starterpack-system
]]

Config.Debug = false                      -- enable debug mode to see more information in the console
Config.CheckVersion = true                -- check for the latest version of the script
Config.DBChecking = true                  -- check if the database table, and columns are initialized properly (only enable this if you are having issues with the database)
Config.CheckPacksCommand = 'checkpacks'   -- command to check all players who have received the starter pack

Config.TargetResource = 'ox_target'       -- supported: ox_target, qb-target
Config.InventoryResource =
'ox_inventory'                            -- supported: ox_inventory, qb-inventory, ps-inventory, qs-inventory, codem-inventory
Config.SQLResource = 'oxmysql'            -- supported: oxmysql, mysql-async, ghmattimysql

Config.UsePlayerLicense = true            -- if you want to use player license to check if they have received the starter pack or not

Config.UseTarget = true                   -- enable target system to interact with the peds
Config.Use3DText = false                  -- enable 3D text to show the interaction text

Config.CommandConfig = {                  -- command to give the starter package
    enable           = false,
    command          = 'starterpack',
    command_help     = 'Get your starter pack',
    starterpack_type = 'normal',
    starter_vehicle  = {
        enable = true,
        model = 'adder',
        random_vehicle = false,
    }
}

Config.DialogInfo = { -- dialog settings for the starter pack
    enable = true,
    title = 'Starter Pack',
    dialog_type = 'rules', -- available types: rules, quiz, captcha (only one type can be enabled)
    alert_description = 'You will receive a starter pack after accepting the rules / completing the quiz/captcha.',

    quiz = {
        questions = {
            {
                question = 'What is the first rule of roleplay?',
                description = 'This question tests your understanding of roleplay basics.',
                answers = {
                    { label = 'Always stay in character',       correct = true },
                    { label = 'Ignore other players',           correct = false },
                    { label = 'Break character for fun',        correct = false },
                    { label = 'Use out-of-character knowledge', correct = false },
                }
            },
            {
                question = 'What should you do if someone is breaking server rules?',
                description = 'This question tests your knowledge of server etiquette.',
                answers = {
                    { label = 'Report them to staff',       correct = true },
                    { label = 'Confront them in-character', correct = false },
                    { label = 'Ignore it and move on',      correct = false },
                    { label = 'Start a fight with them',    correct = false },
                }
            },
            {
                question = 'What does "Fail RP" mean?',
                description = 'This question tests your understanding of roleplay terms.',
                answers = {
                    { label = 'Actions that break roleplay immersion', correct = true },
                    { label = 'Winning a roleplay scenario',           correct = false },
                    { label = 'A type of roleplay event',              correct = false },
                    { label = 'A server rule about driving',           correct = false },
                }
            },
        }
    },

    captcha = {
        captcha_type = 'ra' -- rl: random letters, rn: random numbers, ra: random alphanumeric
    },

    rules = {
        {
            title = 'Rule #1: Stay In Character',
            description =
            'Always remain in character while playing. Breaking character without a valid reason is not allowed.',
        },
        {
            title = 'Rule #2: No Meta-Gaming',
            description =
            'Do not use out-of-character (OOC) knowledge in-character (IC). This includes information from Discord, Twitch, or other sources.',
        },
        {
            title = 'Rule #3: Respect Other Players',
            description =
            'Treat all players with respect. Harassment, hate speech, or toxic behavior will not be tolerated.',
        },
        {
            title = 'Rule #4: No Random Deathmatch (RDM)',
            description = 'Do not engage in random violence or kill other players without a valid roleplay reason.',
        },
        {
            title = 'Rule #5: Follow Server Guidelines',
            description = 'Adhere to all server rules and guidelines. Failure to do so may result in warnings or bans.',
        },
    }
}

Config.Locations = {
    ["1"] = {                                                                       -- Unique identifier for the location
        starterpack_type = 'normal',                                                -- Type of starter pack given to the player (set to false if you don't want to give a starter pack item)
        label            = 'Get your starter pack',                                 -- Target label (shown to the player)
        icon             = 'fa-solid fa-gift',                                      -- Target icon (from FontAwesome)

        coords           = vec4(-1040.479126, -2731.582520, 20.164062, 238.110229), -- Coordinates and heading of the NPC (ped)

        ped              = {                                                        -- Settings for the ped (NPC)
            model = 'a_m_y_business_03',                                            -- Ped model (see the FiveM ped model list)
            scenario = 'Standing',                                                  -- Ped scenario (animation/behavior)
        },

        safezone         = { -- Safe zone settings (optional)
            enable = false,  -- Enable or disable the safe zone
            zone_points = {
                vec3(-1035.819, -2734.205, 20.169),
                vec3(-1035.999, -2727.598, 20.134),
                vec3(-1043.567, -2723.403, 20.126),
                vec3(-1049.598, -2731.540, 20.169),
                vec3(-1041.131, -2739.401, 20.169),
            } -- Define safe zone points (if enabled) using vector3
        },

        starter_vehicle  = {         -- Vehicle settings for players receiving a starter vehicle
            enable = true,           -- Enable or disable the starter vehicle
            model = 'adder',         -- Vehicle model (from FiveM vehicle model list) will be ignored if random_vehicle is set to true
            random_vehicle = true,   -- Spawn a random vehicle from the list (true/false)
            teleport_player = false, -- Teleport player to the vehicle (true/false)
            vehicle_spawns = {       -- Spawn points for the vehicle (multiple spawn locations)
                vec4(-1039.02, -2727.53, 19.65, 243.17),
                vec4(-1043.3, -2725.09, 19.65, 241.12),
                vec4(-1047.57, -2722.66, 19.65, 240.54),
                vec4(-1034.38, -2719.0, 19.65, 240.52),
                vec4(-1038.51, -2716.53, 19.64, 240.34),
            },
            fuel = 100.0, -- Fuel level of the vehicle when spawned
        },

        receiving_radius = 20.0, -- Radius around the location where players can receive the starter pack
        distance         = 2.0,  -- Distance from the ped to interact with it
    },
    -- add more locations here
}

Config.RandomVehicles = { -- list of vehicles to be given randomly to the player
    vehicles = {
        "adder",
        "zentorno",
        "t20",
        "osiris",
        "reaper",
        "tempesta",
        "italigtb",
        "italigtb2",
        "nero",
        -- add more vehicles here
    }
}

Config.StarterPackItems = { -- items that will be given to player
    ["normal"] = {
        { item = 'burger',   amount = 5 },
        { item = 'sprunk',   amount = 5 },
        { item = 'phone',    amount = 1 },
        { item = 'lockpick', amount = 5 },
        { item = 'money',    amount = 5000 },
    },
    -- add more starter pack types here
}

---@param vehicle any
---@param fuel number
---@decription Set fuel level of the vehicle using the fuel resources
Config.SetFuel = function(vehicle, fuel)
    if GetResourceState("LegacyFuel") == "started" then
        exports['LegacyFuel']:SetFuel(vehicle, fuel)
    elseif GetResourceState("cdn-fuel") == "started" then
        exports['cdn-fuel']:SetFuel(vehicle, fuel)
    elseif GetResourceState("ps-fuel") == "started" then
        exports['ps-fuel']:SetFuel(vehicle, fuel)
    elseif GetResourceState("lj-fuel") == "started" then
        exports['lj-fuel']:SetFuel(vehicle, fuel)
    elseif GetResourceState("ox_fuel") == "started" then
        Entity(vehicle).state.fuel = fuel
    else
        warn("Fuel resource not found, please set your fuel resource in the config.lua")
        SetVehicleFuelLevel(vehicle, fuel) -- Fallback to the default fuel system
    end
end

---@param vehicle any
---@return string
---@decription If you have a custom vehicle key system you can give the key to the player
Config.GiveKey = function(vehicle, plate)
    if GetResourceState("wasabi_carlock") == "started" then
        exports.wasabi_carlock:GiveKey(plate)
    elseif GetResourceState("jaksam-vehicles-keys") == "started" then
        TriggerServerEvent("vehicles_keys:selfGiveVehicleKeys", plate)
    elseif GetResourceState("cd_garage") == "started" then
        TriggerEvent('cd_garage:AddKeys', plate)
    elseif GetResourceState("okokGarage") == "started" then
        TriggerServerEvent("okokGarage:GiveKeys", plate)
    elseif GetResourceState("t1ger_keys") == "started" then
        TriggerServerEvent('t1ger_keys:updateOwnedKeys', plate, true)
    elseif GetResourceState("ak47_vehiclekeys") == "started" then
        exports['ak47_vehiclekeys']:GiveKey(plate, false)
    else
        TriggerEvent("vehiclekeys:client:SetOwner", plate)
    end
end

---@param message string
---@param type string
---@param is_server boolean
---@decription Send notification to the player
Config.Notification = function(message, type, is_server, src)
    local Core, Framework = GetCore()
    if is_server then
        if Framework == "esx" then
            TriggerClientEvent("esx:showNotification", src, message)
        else
            TriggerClientEvent('QBCore:Notify', src, message, type, 5000)
        end
    else
        if Framework == "esx" then
            -- TriggerEvent("esx:showNotification", message)
            Core.ShowNotification(message, type, 5000)
        else
            Core.Functions.Notify(message, type, 5000)
        end
    end
end
```

{% endtab %}

{% tab title="server/discordlog.lua" %}

```lua
DiscordConfig = {
    ["webhook"] = "", -- Your webhook here
    ["title"] = "Starterpack Logs",
    ["thumbnail"] = "https://i.imgur.com/6s82WUZ.png",
    ["color"] = "3447003" -- HEX
}
```

{% endtab %}
{% endtabs %}

***

## Using `GetPlayerIdentifiers` vs `Player.identifier` / `Player.PlayerData.citizenid`

***

In this section, we'll compare the use of `GetPlayerIdentifiers` with `Player.identifier` or `Player.PlayerData.citizenid` for player identification in scripts. This comparison will highlight the advantages and drawbacks of each approach, especially in **multicharacter environments**.

**1. `GetPlayerIdentifiers`**

* **Overview**: Retrieves player identifiers like Rockstar license (`license:`), Steam ID (`steam:`), and Discord ID (`discord:`) from external platforms.
* **Best For**: Ensuring a consistent and secure identification method across all characters, as the identifiers are tied to external services.
* **Security**: Difficult to exploit, since these identifiers are tied to accounts outside of the game.
* **Drawback**: Doesn't differentiate between multiple characters for the same player, as the external identifier remains the same across all characters.

**2. `Player.identifier` or `Player.PlayerData.citizenid`**

* **Overview**: These are server framework-dependent identifiers (e.g., `identifier` in ESX and `citizenid` in QBCore) tied to either the player or specific characters.
* **Best For**: Multi-character servers where each character needs a unique identifier.
* **Drawback**: In multi-character setups, it can be exploited. For example, players could delete and recreate characters to bypass mechanisms like starter packs, since these identifiers can change with each new character.

## **Comparison Table**

***

| Aspect                        | GetPlayerIdentifiers                             | Player.identifier / Player.PlayerData.citizenid               |
| ----------------------------- | ------------------------------------------------ | ------------------------------------------------------------- |
| Source                        | External (Rockstar, Steam, Discord)              | Internal (Server Framework - ESX, QBCore, etc.)               |
| Consistency                   | Consistent across all characters                 | Unique to each character (in multi-character setups)          |
| Security                      | Harder to spoof, tied to external accounts       | Easier to exploit, especially in multi-character setups       |
| Multi-Character Support       | Not ideal for differentiating between characters | Ideal for differentiating between characters                  |
| Exploits (e.g., Starter Pack) | Hard to exploit (external ID remains the same)   | Players can delete and recreate characters to exploit         |
| Framework Dependency          | Framework-agnostic                               | Dependent on specific server framework                        |
| Best For                      | Reliable identification across all characters    | Differentiating between characters in multi-character servers |

***

* **Use `GetPlayerIdentifiers`** for more secure, consistent player identification across all characters.
* **Use `Player.identifier` or `Player.PlayerData.citizenid`** to uniquely identify individual characters in multi-character servers, but ensure you have additional measures to prevent exploitation.

{% hint style="info" %}
**Enable`Config.UsePlayerLicense` (set to `true`)** for **secure and consistent player identification across all characters**. This ensures that the player's external identifier (like Rockstar license, Steam ID, or Discord ID) remains the same, preventing exploits like recreating characters to claim rewards again.
{% endhint %}

{% hint style="warning" %}
**Set`Config.UsePlayerLicense` to `false`** if you want to **uniquely identify individual characters** in multi-character servers. However, you should implement **additional safeguards** (e.g., using external identifiers for backup checks) to prevent players from exploiting mechanisms by deleting and recreating characters.
{% endhint %}
