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 )
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
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
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.
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.
Navigate to wert_drugsell/web/build/locales.json.
Open the file with any text editor (VS Code, Notepad++).
Edit the values on the right side to your desired language.
Restart the script.
Note : Also shared/config.lua has some extra locales u can check it also.
OPEN FILES
SHARED/CONFIG.LUA
CLIENT/EDITABLE_CLIENT.LUA
SERVER/EDITABLE_SERVER.LUA
🆘 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.
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!',
}
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)
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