Wert Drug Sell System

You can access the setup information you need about this product


🚀 Installation

Welcome to the Wert Drug Selling System documentation. Follow these steps to install and configure the script on your server.

Note: This script is encrypted using FiveM Asset Escrow system. Ensure your server license key is linked to the same CFX account used for the purchase.

📋 Requirements

Before installing, ensure you have the following dependencies installed and started:

  • Framework: QBCore, ESX, or QBox ( Auto-detected or Configurable )

  • ox_lib (Required for UI and Logic)


🛠️ Step-by-Step Installation

1. Download & Extract

Download the wert_drugsell package from your cfx portal assets. Extract the folder into your server's resources directory.

2. Configure Framework

Open shared/config.lua and ensure the framework settings match your server.

Lua

Config.Framework = 'qb' -- Options: 'qb', 'esx', 'qbox'

3. Database Setup (Auto-Install) ✨

You do not need to run any SQL files manually.

The script includes an Auto-Migration system. When you start the script for the first time, it will automatically create the necessary database tables (wert_drugsell_users, transactions, etc.) and load the dealers.

4. Add Items to Inventory

U can add this items into the ur item list

['drugtablet'] = {
    label = 'Drug Tablet',
    weight = 500,
    stack = false,
    close = true,
    description = 'An encrypted tablet used for illegal network communication.',
    client = {
        image = 'drugtablet.png', -- Make sure to add the image
    }
},

Important: Ensure the item names match exactly what is in your Config.Drugs inside shared/config.lua. If you change item names there, change them here too.

5. Item Images

Copy the images provided in the script folder of the script and paste ur inventory images.

6. Server Config

Add the script to your server.cfg file. Ensure it is started after the dependencies.

ensure oxmysql
ensure ox_lib
ensure ox_inventory

ensure wert_drugsell

7. Restart Server

Restart your server. Watch the server console; you should see a message confirming that the database tables have been checked and dealers have been initialized.


🌍 Localization (Translation)

You can easily translate the entire interface without editing the source code.

  1. Navigate to wert_drugsell/web/build/locales.json.

  2. Open the file with any text editor (VS Code, Notepad++).

  3. Edit the values on the right side to your desired language.

  4. Restart the script.

Note : Also shared/config.lua has some extra locales u can check it also.

"sidebar": {
    "home": "Ana Sayfa", 
    "chat": "Sohbet"
}

OPEN FILES

SHARED/CONFIG.LUA

Config = {}

Config.Debug = false
Config.Framework = 'qb' -- 'qb' or 'esx' or 'qbox'
Config.TabletItem = 'drugtablet'

Config.TabletStream = {
    dict = "amb@code_human_in_bus_passenger_idles@female@tablet@idle_a",
    clip = "idle_a",
    flag = 49,
    model = `prop_cs_tablet`,
    bone = 28422,
    pos = vector3(-0.05, 0.0, 0.0),
    rot = vector3(0.0, 0.0, 0.0)
}

Config.MoneyIcon = "nui://ox_inventory/web/images/money.png"

Config.PoliceAlertChance = {
    active = false,
    param = 10
}

Config.GangControl = { -- Do you want only the gangs to have access?
    active = false, -- active state?
    perms = { -- allowed gangs for system?
        ballas = true,
        vagos = true,
        families = true,
        -- If u want add more
    }
}

Config.CornerSellChance = 50
Config.CornerSellCooldown = 0

Config.Levels = {
    [1] = { requiredXP = 0, label = "Street Rat" },
    [2] = { requiredXP = 500, label = "Runner" },
    [3] = { requiredXP = 1500, label = "Hustler" },
    [4] = { requiredXP = 3500, label = "Supplier" },
    [5] = { requiredXP = 7000, label = "Kingpin" },
}

Config.Drugs = {
    ['weed_ak47'] = {
        label = "Weed Baggy",
        price = { min = 150, max = 220 },
        xp = 10,
        risk = false,
        image = "nui://ox_inventory/web/images/weed_ak47.png"
    },
    ['cokebaggy'] = {
        label = "Bag of Coke",
        price = { min = 300, max = 450 },
        xp = 25,
        risk = true,
        image = "nui://ox_inventory/web/images/cokebaggy.png"
    },
    ['meth'] = {
        label = "Meth Crystal",
        price = { min = 400, max = 600 },
        xp = 35,
        risk = true,
        image = "nui://ox_inventory/web/images/meth_baggy.png"
    }
}

Config.Dealers = {
    ['gustavo'] = {
        name = "Gustavo",
        region = "South Side",
        coords = vector4(-92.3008, -2205.0381, 7.8117, 0.4437), -- Koordinatları ayarla
        model = 'g_m_y_mexgoon_01',
        image = "nui://wert_drugsell/web/images/dealers/gustavo.png"
    },
    ['vlad'] = {
        name = "Little Vlad",
        region = "Downtown",
        coords = vector4(-98.6998, -2205.0425, 7.8117, 2.4237),
        model = 'a_m_y_business_02',
        image = "nui://wert_drugsell/web/images/dealers/littlevlad.png"
    }
}

Config.MessageItemControl = true -- # For the get messages from buyer, player must be a drug tablet in inventory.
Config.MessageChance = { -- Do you want an extra chance check so that the message can be sent to the player?
    active = false,
    param = 10, -- Max 100
}
Config.MessageSettings = {
    minTime = 2, -- Min Time For Get Message 2
    maxTime = 5, -- Max Time For Get Message 5
    npcNames = { "Unknown", "Customer", "Junkie", "Blue", "Ghost", "T-Bone" },
    maxPendingLimit = 3,   -- How many unread messages can a player have?
    expirationTime = 30,    -- How many minutes should the message be deleted after?
    allowExpire = true, -- expirationTime? can work ?
    locations = {
        { label = "Grove St. Gas Station", coords = vector3(-62.8336, -1784.8881, 26.9940), heading = 141.2766 },
        { label = "Mirror Park", coords = vector3(1113.1360, -636.4269, 55.8128), heading = 99.8651 },
        { label = "Vespucci Canals", coords = vector3(-1100.9879, -1196.3208, 1.3549), heading = 303.2260 },
        -- Buraya daha fazla koordinat ekle
    }
}


Config.BuyerPeds = {
    'a_m_y_beach_01', 'a_m_y_genstreet_01', 'g_m_y_ballaeast_01', 
    'a_f_y_hipster_01',
}

Config.CornerPositions = {
    { pos = vector4(-1179.1772, -1509.5145, 4.3453, 205.0501), distance = 150.0 },
    { pos = vector4(14.3249, -1663.2289, 29.2768, 318.2131), distance = 150.0 },
    { pos = vector4(209.6659, -71.7806, 69.0762, 40.8674), distance = 150.0 }
}

Config.SomeLangs = {
    locationSet = "Buyer location set. Go meet them.",
    permission = 'You are not have permission for that!',
    goDealer = "Go to %s to collect cash.",
    itemError = "You don't have the items!",
    noFunds = "No funds to collect.",
    soldMessage = "Sold %sx %s for $%s",
    collectedMessage = "Collected $%s from %s",
    noNeedItem = 'You are not have enough item!',
}
CLIENT/EDITABLE_CLIENT.LUA

Framework = nil
local oxInventoryActive = GetResourceState('ox_inventory') == 'started'
if Config.Framework == 'qb' or Config.Framework == 'qbox' then
    Framework = exports['qb-core']:GetCoreObject()
elseif Config.Framework == 'esx' then
    Framework = exports["es_extended"]:getSharedObject()
end

-- # Global Variables

drugSellDuty = false
MyGang = 'nil'
drugSelectedItems = {}

local function LoadPlayerMetas()
    Wait(1000)
    local myPlayerData = lib.callback.await('wert_drugsell:server:load-player-meta', false)
    drugSellDuty = myPlayerData.drugSellDuty
    drugSelectedItems = myPlayerData.drugSelectedItems
    MyGang = myPlayerData.MyGang
end

function SelectCustomNotify(text, style, duration)
    lib.notify({ title = 'Drug Sell', description = text, type = style, duration = duration })
end

function CheckPoliceAlert(data)
    if not data then return end
    -- data table inners if u want use in police call
    --[[ data.label -> Label
    data.image -> Image
    data.amount -> Amount
    data.price -> Price ]]
    -- data.type -> 'mission_sell' or 'dealer_collect' or 'corner_sell'
    local pos = GetEntityCoords(cache.ped) -- # Alert Position

    -- Add ur police alert export
end

function CheckHasItem(key)
    if oxInventoryActive then
        local itemCount = exports.ox_inventory:GetItemCount(key)
        if itemCount and itemCount > 0 then
            return true
        end
        return false
    end
    if Config.Framework == 'qb' or Config.Framework == 'qbox' then
        return QBCore.Functions.HasItem(key)
    end
    return false
end

function WertGetPeds(ignoreList)
    ignoreList = ignoreList or {}
    local ents = GetGamePool('CPed')
    local entities = {}
    local ignoreMap = {}
    for i = 1, #ignoreList do
        ignoreMap[ignoreList[i]] = true
    end
    for i = 1, #ents do
        local entity = ents[i]
        if not ignoreMap[entity] then
            entities[#entities + 1] = entity
        end
    end
    return entities
end

RegisterNetEvent('wert_drugsell:client:custom-select-notify', SelectCustomNotify)

AddEventHandler('onResourceStart', function(resource)
    if resource ~= GetCurrentResourceName() then return end
    LoadPlayerMetas()
end)

RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
    LoadPlayerMetas()
end)

RegisterNetEvent('esx:playerLoaded', function()
    LoadPlayerMetas()
end)
SERVER/EDITABLE_SERVER.LUA

Framework = nil
Bridge = {}
if Config.Framework == 'qb' or Config.Framework == 'qbox' then
    Framework = exports['qb-core']:GetCoreObject()
elseif Config.Framework == 'esx' then
    Framework = exports["es_extended"]:getSharedObject()
end

local function SaveMetadataToSQL(citizenid, data)
    if not citizenid then return end
    MySQL.update('UPDATE wert_drugsell_users SET metadata = ? WHERE citizenid = ?', { json.encode(data or {}), citizenid })
end

local function GetMetadaFromSQL(citizenid, includeUserData)
    local defaultMeta = { drug_duty = false, drug_selecteditems = {} }
    local userData = MySQL.single.await('SELECT * FROM wert_drugsell_users WHERE citizenid = ?', {citizenid})
    if not userData then
        MySQL.insert.await('INSERT INTO wert_drugsell_users (citizenid, metadata) VALUES (?, ?)', { citizenid, json.encode(defaultMeta) })
        if includeUserData then
            userData = { xp = 0, level = 1, settings = nil, metadata = defaultMeta }
            return userData
        end
        return defaultMeta
    end
    userData.metadata = userData.metadata and json.decode(userData.metadata) or defaultMeta
    if includeUserData then
        userData.settings = userData.settings and json.decode(userData.settings) or nil
        return userData
    end
    return userData.metadata
end

function Bridge.GetPlayer(src)
    if not src then return nil end
    if Config.Framework == 'qb' or Config.Framework == 'qbox' then
        return Framework.Functions.GetPlayer(src)
    else
        return Framework.GetPlayerFromId(src)
    end
end

function Bridge.GetPlayerByIdentifier(identifier)
    if not identifier then return nil end
    if Config.Framework == 'qb' or Config.Framework == 'qbox' then
        return Framework.Functions.GetPlayerByCitizenId(identifier)
    else
        return Framework.GetPlayerFromIdentifier(identifier)
    end
end


function Bridge.GetPlayerIdentifier(ply)
    if not ply then return nil end
    if Config.Framework == 'qb' or Config.Framework == 'qbox' then
        return ply.PlayerData.citizenid
    end
    return ply.getIdentifier()
end

function Bridge.AddMoney(src, account, amount)
    local ply = Bridge.GetPlayer(src)
    if not ply then return end
    amount = tonumber(amount)
    if Config.Framework == 'qb' or Config.Framework == 'qbox' then
        ply.Functions.AddMoney(account, amount)
    else
        if account == 'cash' then
            ply.addMoney(amount, "Drug Sell System")
        else
            ply.addAccountMoney(account, amount, "Drug Sell System")
        end
    end
end


function Bridge.RemoveItem(src, item, amount)
    local ply = Bridge.GetPlayer(src)
    if not ply then return end
    amount = tonumber(amount)
    if GetResourceState('ox_inventory') == 'started' then
        local success = exports.ox_inventory:RemoveItem(src, item, amount)
        return success
    end
    if Config.Framework == 'qb' or Config.Framework == 'qbox' then
        local item = ply.Functions.GetItemByName(item)
        if item and item.amount >= amount then
            ply.Functions.RemoveItem(item, amount)
            return true
        end
    else
        local item = ply.getInventoryItem(item)
        if item and item.count >= amount then
            ply.removeInventoryItem(item, amount)
            return true
        end
    end
    return false
end

function Bridge.CanRemoveItem(src, item, amount)
    local ply = Bridge.GetPlayer(src)
    if not ply then return end
    amount = tonumber(amount)
    if GetResourceState('ox_inventory') == 'started' then
        local itemCountt = exports.ox_inventory:GetItemCount(src, item)
        if not itemCountt then itemCountt = 0 end
        if itemCountt >= amount then
            return true
        end
        return false
    end
    if Config.Framework == 'qb' or Config.Framework == 'qbox' then
        local item = ply.Functions.GetItemByName(item)
        if item and item.amount >= amount then
            return true
        end
    else
        local item = ply.getInventoryItem(item)
        if item and item.count >= amount then
            return true
        end
    end
    return false
end

function Bridge.SetDuty(src, state)
    local ply = Bridge.GetPlayer(src)
    if not ply then return end
    local citizenid = Bridge.GetPlayerIdentifier(ply)
    local metadata = GetMetadaFromSQL(citizenid)
    metadata.drug_duty = state
    SaveMetadataToSQL(citizenid, metadata)
end

function Bridge.SetSelectedItems(src, data)
    local ply = Bridge.GetPlayer(src)
    if not ply then return end
    local citizenid = Bridge.GetPlayerIdentifier(ply)
    local metadata = GetMetadaFromSQL(citizenid)
    metadata.drug_selecteditems = data
    SaveMetadataToSQL(citizenid, metadata)
end

function Bridge.GetUIComponents(ply, includeUserData)
    if not ply then return nil end
    local citizenid = Bridge.GetPlayerIdentifier(ply)
    local userData = GetMetadaFromSQL(citizenid, includeUserData)
    local metadata = includeUserData and userData.metadata or userData
    if Config.Framework == 'qb' or Config.Framework == 'qbox' then
        return {
            name = ply.PlayerData.charinfo.firstname .. " " .. ply.PlayerData.charinfo.lastname,
            cash = ply.PlayerData.money['cash'],
            isDuty = metadata.drug_duty,
            selectedItems = metadata.drug_selecteditems or {},
            gang = ply.PlayerData.gang.name,
            userData = includeUserData and userData or nil
        }
    else
        return {
            name = ply.getName(),
            cash = ply.getMoney(),
            isDuty = metadata.drug_duty,
            selectedItems = metadata.drug_selecteditems or {},
            gang = 'none', -- If u use any gang system please provide export !IMPORTANT FOR ESX USERS
            userData = includeUserData and userData or nil
        }
    end
end

function Bridge.FramePlayers()
    if Config.Framework == 'qb' or Config.Framework == 'qbox' then
        return Framework.Functions.GetPlayers()
    else
        return Framework.GetPlayers()
    end
end

function Bridge.Source(ply)
    if not ply then return 0 end
    if Config.Framework == 'qb' or Config.Framework == 'qbox' then
        return ply.PlayerData.source
    else
        return ply.source
    end
end

function Bridge.CheckTablet(ply, src)
    if not ply then return false end
    if GetResourceState('ox_inventory') == 'started' then
        local tabletCount = exports.ox_inventory:GetItemCount(src, Config.TabletItem)
        if not tabletCount then tabletCount = 0 end
        if tabletCount > 0 then return true end
        return false
    end
    if Config.Framework == 'qb' or Config.Framework == 'qbox' then
        local item = ply.Functions.GetItemByName(Config.TabletItem)
        if item and item.amount > 0 then
            return true
        end
    else
        local item = ply.getInventoryItem(Config.TabletItem)
        if item and item.count > 0 then
            return true
        end
    end
    return false
end

-- # Item Use

if Config.Framework == 'qb' or Config.Framework == 'qbox' then
    Framework.Functions.CreateUseableItem(Config.TabletItem, function(source)
        TriggerClientEvent('wert_drugsell:client:openTablet', source)
    end)
else
    Framework.RegisterUsableItem(Config.TabletItem, function(playerId)
        TriggerClientEvent('wert_drugsell:client:openTablet', tonumber(playerId))
    end)
end

🆘 Support

If you encounter any issues during installation, please check the server console for errors first. For further assistance, join our Discord Server and open a ticket.

Last updated