> For the complete documentation index, see [llms.txt](https://theftdev.gitbook.io/theftdev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://theftdev.gitbook.io/theftdev/theftdev-scripts/resources/drug-phone/installation.md).

# Installation

## Dependencies

{% tabs %}
{% tab title="QBCore" %}
QBCore Framework
{% endtab %}

{% tab title="ESX" %}
ESX Framework
{% endtab %}
{% endtabs %}

***

## How to install

Drag the script in your folder

Add the following item to `yourinventory/data/items.lua`\
QBCore users to `qbcore/shared/items.lua`\
\
Add the item image to your inventory/images

Run the `SQL` & restart your server.

{% hint style="info" %}
If you are using a different inventory then literally create the same items for your custom inventory.
{% endhint %}

{% tabs %}
{% tab title="QBCore" %}

```lua
-- Drug Phone
drugphone = { 
    name = 'drugphone', 
    label = 'Drug Phone', 
    weight = 0, 
    type = 'item', 
    image = 'drugphone.png', 
    unique = true, 
    useable = false, 
    shouldClose = false, 
    combinable = nil, 
    description = 'What a great Business Phone' 
},
```

{% endtab %}

{% tab title="ESX" %}

```lua
-- Drug Phone
['drugphone'] = {
  label = 'Drug Phone',
  weight = 0,
  client = {
    image = 'drugphone.png',
  },
},
```

{% endtab %}
{% endtabs %}

<figure><img src="https://dunb17ur4ymx4.cloudfront.net/packages/images/a476a844105f9e4f5560b397a3232f435d81bc05.gif" alt=""><figcaption></figcaption></figure>

***

* **StreetDealXP — XP per successful street deal**\
  Amount of XP granted each time a player completes (accepts) a street deal. Default: `2`.
* **DrugLevel — Level thresholds (cumulative XP)**\
  Total XP required to reach each level:\
  `1: 0, 2: 500, 3: 1,500, 4: 3,000, 5: 5,000, 6: 8,000, 7: 12,000, 8: 15,000, 9: 17,500, 10: 20,000`\
  *Note:* Values are cumulative; add more entries to extend the cap.

```lua
-- XP awarded for successful street deals (per accept)
Config.StreetDealXP = 2
-- Level/XP
Config.DrugLevel = {
    [1] = 0,
    [2] = 500,
    [3] = 1500,
    [4] = 3000,
    [5] = 5000,
    [6] = 8000,
    [7] = 12000,
    [8] = 15000,
    [9] = 17500,
    [10] = 20000,
}
```

***

* **DrugBuyers — Buyer categories**\
  Top-level list of drug buyer setups, grouped by category (e.g., Weed).
* **CategoryName — Display name**\
  The category label shown in UI/menus.
* **ItemList — Sellable items**\
  Array of items this category buys.
  * **Item**: Internal item name.
  * **Label**: UI display name.
  * **img**: Icon/texture key used in UI.
  * **minPrice / maxPrice**: Random sell price range per unit.
  * **allowStreetDeal**: Item can be sold on the street (true/false).
  * **allowDealerDeal**: Item can be sold to a dealer/NPC (true/false).
* **DrugContacts — Progression contacts**\
  NPC contacts unlocked by level; each entry:
  * **ContactName**: NPC name.
  * **Level**: Required player level to access.
  * **XP**: XP granted/used by your contact logic.
* **DrugBuyerLocations — Street buyer spawns**\
  List of spawn points as `{ x, y, z, heading }` for street deals.
* **Example (Weed)**\
  Includes street items like Joint and 2g strains (AK47, Amnesia, etc.) and a dealer-only **Weed Brick 100g** with higher price range.

```lua
[1] = {
    CategoryName = "Test Category",
    ItemList = {
        { Item= "item_name", Label= "Item Name", img= "img_name", minPrice= 50, maxPrice= 60, allowStreetDeal= false, allowDealerDeal= true },
    },
    DrugContacts = {
        { ContactName= "Phil Morb", Level= 1, XP= 100 },
        { ContactName= "Denis Klaf", Level= 2, XP= 100 },
    },
    DrugBuyerLocations = {
        -- x, y, z, heading
        { 339.48, -217.0, 54.22, 66.55 },
    },
},
```

<figure><img src="https://dunb17ur4ymx4.cloudfront.net/packages/images/edf0b75067e0bd746a71fc7b3840f8ea430594c5.gif" alt=""><figcaption></figcaption></figure>

***

* **DealTuning — Price & tension logic**\
  Master settings for street-deal success chance and tension effects.
* **HardCapMult — Price ceiling**\
  Max allowed offer = `item.maxPrice * 1.10`.
* **Tension — Bounds**\
  NPC tension scale: `0–100`.
* **DealDelays.MaxFailures — Auto-fail attempts**\
  Failed/hesitated tries at a spot before auto-fail: `3`.
* **UnderMin — Price ≤ minPrice**\
  Treated as success; tension drops `-2 … -1`.
* **WithinRange — minPrice < price ≤ maxPrice**\
  Chance = `BaseAtMin (85) − floor(pct * DropAcrossRange (20))`,\
  with `pct = (price−min)/(max−min)`, +`FirstDealBonus (5)`, clamped by `MinBaseChance (40)`.\
  On success: tension `-1 … 0`. On fail: tension `+2 … +6`; show `"The buyer hesitates..."`.
* **OverCap — maxPrice < price ≤ hardCap**\
  Chance = `AtMaxPrice (10) − floor(overPct * DropPerOverPct (50))`,\
  with `overPct = (price−max)/max(max,1)`, min `0`.\
  Success: tension `+10 … +15`. Fail: tension `+20 … +35`; show `"Too expensive..."`.
* **AboveHardCap — price > hardCap**\
  Always fail; tension `+30 … +45`; show `"Ridiculous price!"`.

```lua
-- Dealer deal price/tension tuning extracted from server logic
Config.DealTuning = {
    HardCapMult = 1.10,
    Tension = {
        Min = 0,
        Max = 100,
    },
    DealDelays = {
        MaxFailures = 3,
    },

    -- Case: price <= minPrice
    UnderMin = {
        TensionDelta = { Min = -2, Max = -1 },
    },

    -- Case: minPrice < price <= maxPrice
    WithinRange = {
        -- Chance formula: baseChance = BaseAtMin - floor(pct * DropAcrossRange)
        -- pct = (price - minPrice) / (maxPrice - minPrice)
        BaseAtMin       = 85,
        DropAcrossRange = 20,
        FirstDealBonus  = 5,
        MinBaseChance   = 40,

        -- On success: small tension decrease
        SuccessTensionDelta = { Min = -1, Max = 0 },
        -- On fail: tension increase and delay increments
        FailTensionDelta    = { Min = 2,  Max = 6 },
        FailMessage         = "The buyer hesitates... try a better price.",
    },

    -- Case: maxPrice < price <= hardCap
    OverCap = {
        -- Chance formula: chance = AtMaxPrice - floor(overPct * DropPerOverPct)
        -- overPct = (price - maxPrice) / max(maxPrice, 1)
        AtMaxPrice      = 10,
        DropPerOverPct  = 50,   -- 0.20 over => -10 => 0% chance
        MinChance       = 0,

        SuccessTensionDelta = { Min = 10, Max = 15 },
        FailTensionDelta    = { Min = 20, Max = 35 },
        FailMessage         = "Too expensive. Lower your price.",
    },

    -- Case: price > hardCap
    AboveHardCap = {
        TensionDelta = { Min = 30, Max = 45 },
        FailMessage  = "Ridiculous price! Don't try to rip me off.",
    },
}
```

<figure><img src="https://dunb17ur4ymx4.cloudfront.net/packages/images/368d19c71e26847fe098c06864777466265f174f.gif" alt=""><figcaption></figcaption></figure>
