Developers
The drug sales server and client exports, its notification event and state bag, and the open functions for prices, payouts, police counts, dispatch and sale checks.
Every export is called on exports.lation_selling. Server exports that act on a player take their server id as source; client exports work on the local player. A player's identifier is the ESX identifier on ESX and the citizenid on Qbox and QBCore.
Server exports
| Export | Returns |
|---|---|
GetData(source, type?) | A player's record, or one field of it |
AddData(source, amount, dataType) | Nothing |
CheckLevel(source) | Nothing |
PoliceCount() | Police on duty |
TotalSales(source, zoneId) | Drugs the player sold in a capped zone this session |
GetData
Server export
local data = exports.lation_selling:GetData(source, type)Parameters
sourcenumber- The player's server id
typestringoptionaldefaultnil- One field:
level,rep,total_salesortotal_earned. The whole record when left out.
Returns
table | number | nil- The record (below), or the value of
type.nilwhen the player isn't loaded in your framework.
The first time a player is looked up, their row is read from the lation_selling table, or created at level 1. The record is the cached one, so treat it as read-only and change it with AddData.
{
level = 2,
rep = 4120, -- earned since the last level up; held at levelUp at the top level
total_sales = 318, -- drugs sold, all time
total_earned = 52440, -- money made, all time
identifier = 'ABC12345', -- present once the record has come from the table
}local level = exports.lation_selling:GetData(source, 'level')
if level and level >= 3 then
-- unlock something
endAddData
Server export
exports.lation_selling:AddData(source, amount, dataType)Parameters
sourcenumber- The player's server id
amountnumber- How much to add. Negative numbers and anything that isn't a number do nothing.
dataTypestringrep,level,total_salesortotal_earned
Returns
- Nothing
Adding rep doesn't level the player up on its own: call CheckLevel after it. At the top level, rep can't be added. Nothing is written straight away: records are saved when the player leaves, when the resource stops and when txAdmin shuts the server down.
exports.lation_selling:AddData(source, 500, 'rep')
exports.lation_selling:CheckLevel(source)CheckLevel
Server export
exports.lation_selling:CheckLevel(source)Parameters
sourcenumber- The player's server id
Returns
- Nothing
If the player's rep has reached Config.Reputation.levelUp, raises their level by as many levels as it covers, keeps the rest as rep, shows "Congratulations, you've leveled up!" and writes the leveled log when it's on. Does nothing at the top level. Every sale calls it.
PoliceCount
Server export
local police = exports.lation_selling:PoliceCount()Returns
number- Players with a job in
Config.Police.jobs; on Qbox and QBCore, only those on duty
This is GetPoliceCount in server/functions.lua, so a change there changes the export too.
TotalSales
Server export
local sold = exports.lation_selling:TotalSales(source, zoneId)Parameters
sourcenumber- The player's server id
zoneIdnumber- The zone's index in
Config.Zones
Returns
number- Drugs the player has sold in that zone since drug sales last started
Sales are only counted in zones with limit on, toward their cap. In any other zone it stays 0.
Client exports
| Export | Returns |
|---|---|
GetData(type?) | The local player's record, or one field of it |
PoliceCount() | Police on duty |
TotalSales(zoneId) | Drugs the local player sold in a capped zone this session |
All three ask the server, so call them from a thread, not every frame.
GetData (client)
Client export
local data = exports.lation_selling:GetData(type)Parameters
typestringoptionaldefaultnil- One field:
level,rep,total_salesortotal_earned
Returns
table | number- The record or the field, as the server export returns it.
0when there is none.
local level = exports.lation_selling:GetData('level')PoliceCount (client)
Client export
local police = exports.lation_selling:PoliceCount()Returns
number- The same count as the server export
TotalSales (client)
Client export
local sold = exports.lation_selling:TotalSales(zoneId)Parameters
zoneIdnumber- The zone's index in
Config.Zones
Returns
number- The same count as the server export
Events
lation_selling:Notify
Client event
TriggerClientEvent('lation_selling:Notify', source, message, type)Parameters
messagestring- The text
typestringsuccess,error,informand the like, as your notification system reads them
Send it from the server to show a notification through Config.Setup.notify, titled "Drugs".
TriggerClientEvent('lation_selling:Notify', source, 'A new buyer is asking around Vespucci', 'inform')State bag
drugSale
Entity state bag
local state = Entity(ped).state.drugSaleReturns
string | nil'pending'while a player has that ped's menu open,'sold'once the ped has dealt, refused or been sent away,nilbefore
Set by the server and seen by every client. A ped that is pending or sold can't be sold to, by anyone. Your own scripts can read it, for example to skip peds that have already dealt.
Server functions
server/functions.lua ships open. drug sales calls these functions by name, so keep each one defined with the same arguments when you edit it.
DrugSold
Server function
function DrugSold(source, zoneId, item, quantity, value, xpAdded, metadata) endParameters
sourcenumber- The seller's server id
zoneIdnumber- The zone's index in
Config.Zones itemstring- The item sold
quantitynumber- How many
valuenumber- What the seller was paid
xpAddednumber- The reputation the sale gave
metadatatable | nil- The item's metadata, such as
purity
Called after every completed sale, once the item is taken and the seller is paid. It ships with an example for a gang script that does nothing until you edit it.
function DrugSold(source, zoneId, item, quantity, value, xpAdded, metadata)
if metadata and metadata.purity == 100 then
-- a perfect batch: reward it in your own script
TriggerEvent('my_gangs:addRespect', source, 10 * quantity)
end
end(my_gangs:addRespect stands for your own script's event.)
ItemsClaimed
Server function
function ItemsClaimed(source, item, quantity) endParameters
sourcenumber- The player's server id
itemstring- The item taken back
quantitynumber- How many
Called when a player takes back drugs a buyer robbed them of. Empty by default.
CreateSaleQuote
Server function
function CreateSaleQuote(source, zoneId, item, itemCount) endParameters
sourcenumber- The seller's server id
zoneIdnumber- The zone's index in
Config.Zones itemstring- The item
itemCountnumber- How many the seller carries
Returns
table | nil- The quote (below), or
nilto leave the drug out of the menu
Works out each drug's offer when the menu opens, as described under prices: the purity or the zone's range, the police risk, the level's boost and the quantity. The server keeps the quote and pays its total if the sale goes through.
{
price = 120, -- one, before bonuses ("Buyer will buy for")
difference = 18, -- what police risk adds to one ("Risk bonus")
unitPrice = 144, -- one, with both bonuses
quantity = 1, -- "Buyer wants a total of"
total = 144, -- "Total sale is worth", what is paid
missingMetadata = false, -- true when a Config.Metadata item had no value
}PayPlayer
Server function
function PayPlayer(source, zoneId, item, amount) endParameters
sourcenumber- The seller's server id
zoneIdnumber- The zone's index in
Config.Zones itemstring- The item sold
amountnumber- The sale's total
Pays the zone's money, as described under money. Edit it to pay another way, for example into a gang's account.
GetPoliceCount
Server function
function GetPoliceCount() endReturns
number- Police on duty
Used for police risk, for zones that need police, and by the PoliceCount exports.
GetMetadata
Server function
function GetMetadata(source, item) endParameters
sourcenumber- The player's server id
itemstring- The item
Returns
table | nil- The metadata of the first stack of that item the player carries
Reads purity for purity pricing, and keeps a robbed item's metadata so it comes back the same.
PlayerLog
Server function
function PlayerLog(source, title, message) endParameters
sourcenumber- The player's server id
titlestring- The log's title from
Strings.Logs messagestring- The filled-in message
Sends a log to the service in Logs.Service. See logs.
Client functions
client/functions.lua ships open too. The ones you're most likely to edit:
CanSell
Client function
function CanSell(zoneId) endParameters
zoneIdnumber- The zone's index in
Config.Zones
Returns
booleanfalseto stop the sale
Asked each time a player starts a sale, before the menu opens. By default it stops a player in a vehicle with "You cannot sell from inside your vehicle".
function CanSell(zoneId)
if IsPedInAnyVehicle(cache.ped, true) then
ShowNotification(Strings.Notify.noVehicle, 'error')
return false
end
-- Rockford Hills (zone 6) only deals with players carrying a burner phone (ox_inventory)
if zoneId == 6 and exports.ox_inventory:Search('count', 'burner_phone') < 1 then
ShowNotification('Nobody here trusts you without a burner', 'error')
return false
end
return true
endPoliceDispatch
Client function
function PoliceDispatch(data) endParameters
data.coordsvector3- Where the seller stands
data.streetstring- The street's name
Sends the police alert for the dispatch in Config.Setup.dispatch. Add yours under the custom branch; see dispatch.
The rest
| Function | What it does |
|---|---|
ShowNotification(message, type) | Shows a notification through Config.Setup.notify, with a custom slot |
ShowTextUI(text, icon), HideTextUI(label) | The prompts, through the textui line at the top of the file |
RegisterMenu(data), ShowMenu(menuId) | The menu, through Config.Setup.menu |
AddTargetGlobal, AddTargetEntity, RemoveTargetGlobal, RemoveTargetEntity | The target options, through Config.Setup.target |
SetEntityEvents(entity), ClearEntityEvents(entity) | Hold a buyer still, facing the seller and unhurt while the menu is open, then let them go |
Open files
| Path | What it's for |
|---|---|
config.lua | Every option; see configuration |
strings.lua | Every line players read |
logs.lua | Logging, read by the server only |
bridge/client.lua, bridge/server.lua | Framework and inventory support, with slots for a custom framework or inventory |
client/functions.lua | Notifications, prompts, menus, targets, dispatch and CanSell |
server/functions.lua | Prices, payouts, the police count, metadata, logging and the sale hooks |
Still stuck? Ask in our Discord: the people who write the scripts answer.
Last updated