Installation Guide

Step-by-step setup for Oxide Drugselling — prerequisites, supported inventories, load order, the four phone items, dirty money, database, first-time setup in game, and verification.

Step-by-step setup for oxide-drugselling. Follow the steps in order — most problems come from skipping one.

Prerequisites

Required Resources

These must be installed and working before you start oxide-drugselling:

ResourceMinimum VersionPurpose
ox_libany recentTranslations and helpers
oxmysqlany recentConnects the server to your MySQL database, where phones, clients, messages, heat and settings are saved
o-link1.9.1The bridge between this script and your framework (players, inventory, money, jobs, notifications, targeting, and the tool used to place drop spots)
A targeting resourceanyThe "look at it and pick an option" menu that shows Offer Drugs on pedestrians. o-link supports ox_target, qb-target, sleepless_interact, tgiann-target and oxide-target
A supported inventorysee belowHolds the drugs, the phones and the dirty money

Why o-link 1.9.1?

Version 1.9.1 puts a police alert's map blip where the sale happened when you don't run a dispatch resource. Before it, the blip landed on whichever officer received the alert. Dead drop spots and no-signal areas are also placed in the world with o-link's placement tool. If your o-link doesn't have it, the Place in world and Draw new zone buttons in the settings menu say "In-world placement needs an updated o-link. Update o-link to use this."

If you already run other Oxide resources, you have ox_lib, oxmysql and o-link. Check that your o-link is 1.9.1 or newer.

Supported Frameworks

FrameworkSupport
QBCoreFull
QBX (qbx_core)Full
ESXFull, with a supported inventory (see below)
OthersAny framework o-link supports

o-link is what lets this one script run on all of these. You install it once, and oxide-drugselling finds your framework on its own. There's nothing framework-specific to set in the script.

Which inventory you need

Each trap phone is an inventory item with a hidden ID attached to it. That hidden information on an item is called metadata. The ID is how the phone keeps its own number and client book, so your inventory must be one o-link supports, and it must keep metadata on items.

FrameworkInventoryWorks?
QBXox_inventory (QBX's default)Yes
QBCoreqb-inventory (QBCore's default)Yes, with trap_phone set to unique = true (the block in Adding the items already does this)
QBCoreox_inventoryYes
ESXox_inventoryYes
ESXESX's own built-in inventoryNo. o-link doesn't support it, so nothing can be given or taken
ESXhex_4_inventoryPartly. It drops item metadata, so each character gets one phone tied to them instead of to the item: handing the phone over doesn't hand over its clients, and police can't read a seized phone. Drugs also lose the quality stored on them

Installation Steps

Place the resource

Put the oxide-drugselling folder inside your server's resources folder. If you run several Oxide resources, keep them together in a folder named [oxide].

Check how sale money is paid

See Dirty money. The default works on stock QBCore, QBX and ESX.

Restart your server

Your inventory loads the new items and the resource creates its database tables.

Set it up in game

See First-Time Setup In Game: check the settings and the corner demand, and decide where players get phones.

There's nothing to build or compile. The interface ships ready to use.

Load Order

Your server.cfg is the text file that tells your server which resources to start, and in what order. Every Oxide resource uses the same four-tier order:

server.cfg
# 1. Framework — everything your framework requires (qb-core, es_extended, qbx_core, etc.)
ensure <framework>

# 2. Scripts — your other resources (phone, inventory, garages, etc.)
ensure <your-other-scripts>

# 3. o-link — the bridge. Starts after your framework/scripts, before any Oxide resource.
ensure o-link

# 4. Oxide resources — keep these together, ideally in a folder named [oxide]
ensure oxide-drugselling
  • ox_lib and oxmysql belong with your framework in tier 1.
  • Your inventory, targeting, dispatch and MDT resources go in tier 2.
  • There's no required order inside a tier. What matters is that o-link starts after your framework and scripts, and before oxide-drugselling.
  • If all your Oxide resources are in an [oxide] folder, you can write ensure [oxide] once instead of one line per resource.

Framework Setup

Adding the items

oxide-drugselling adds four items. They must exist in your inventory with the exact names below. None of these names exist on stock QBCore, QBX or ESX, so you don't need to rename anything.

ItemLabelWeight (g)StackableMust be usableWhat it does
trap_phoneTrap Phone150NoYesThe burner phone. Using it opens the phone
trap_simPrepaid SIM10YesYesGives a phone a new number
trap_chargerBattery Pack100YesYesCharges a phone once
sting_phoneSting Phone150NoYesThe police sting phone

"Must be usable" means a player can use the item from their inventory. The script decides what happens; your inventory just has to allow it.

The labels, weights and descriptions are suggestions. Change them to taste. The names must match exactly (or you rename them in the settings menu, see Configuration → Phone).

Pick the tab for your inventory. Do only one.

This covers QBX, and any QBCore or ESX server running ox_inventory. All four items are ready to paste in items/ox_inventory_items.lua in the resource folder.

  1. Open items/ox_inventory_items.lua from the oxide-drugselling folder in a text editor.
  2. Copy every line between return { and the final }.
  3. Open ox_inventory/data/items.lua and paste those lines just above that file's final closing }.
  4. Save the file.
ox_inventory/data/items.lua
['trap_phone'] = { label = 'Trap Phone', weight = 150, stack = false, close = true, description = 'A cheap prepaid phone. Every name in it is a customer' },
['trap_sim'] = { label = 'Prepaid SIM', weight = 10, stack = true, close = true, description = 'A fresh number for a burner phone' },
['trap_charger'] = { label = 'Battery Pack', weight = 100, stack = true, close = true, description = 'A one-shot battery pack for a burner phone' },
['sting_phone'] = { label = 'Sting Phone', weight = 150, stack = false, close = true, description = 'A department phone for undercover buys' },

On QBX, add them here in ox_inventory/data/items.lua, not in qbx_core/shared/items.lua. You don't set a "usable" switch in ox_inventory; oxide-drugselling registers the items it uses itself.

Open qb-core/shared/items.lua, paste this block just above the file's final closing }, and save:

qb-core/shared/items.lua
-- oxide-drugselling
trap_phone   = { name = 'trap_phone',   label = 'Trap Phone',   weight = 150, type = 'item', image = 'trap_phone.png',   unique = true,  useable = true, shouldClose = true, description = 'A cheap prepaid phone. Every name in it is a customer' },
trap_sim     = { name = 'trap_sim',     label = 'Prepaid SIM',  weight = 10,  type = 'item', image = 'trap_sim.png',     unique = false, useable = true, shouldClose = true, description = 'A fresh number for a burner phone' },
trap_charger = { name = 'trap_charger', label = 'Battery Pack', weight = 100, type = 'item', image = 'trap_charger.png', unique = false, useable = true, shouldClose = true, description = 'A one-shot battery pack for a burner phone' },
sting_phone  = { name = 'sting_phone',  label = 'Sting Phone',  weight = 150, type = 'item', image = 'sting_phone.png',  unique = true,  useable = true, shouldClose = true, description = 'A department phone for undercover buys' },

Keep unique = true on trap_phone

When qb-inventory adds an item that isn't unique, it stacks it onto an existing one and throws away the new item's hidden ID. Two phones would merge into one, and a phone would lose its number and clients. If you added trap_phone before without it, change it to unique = true and restart the server.

Some ESX inventories read their items from the items table in your database. If yours does, open your database tool (for example HeidiSQL or phpMyAdmin), run this once, then restart the server:

INSERT INTO items (name, label, weight, rare, can_remove) VALUES
('trap_phone',   'Trap Phone',   1, 0, 1),
('trap_sim',     'Prepaid SIM',  1, 0, 1),
('trap_charger', 'Battery Pack', 1, 0, 1),
('sting_phone',  'Sting Phone',  1, 0, 1);

If your ESX server runs ox_inventory, use the ox_inventory tab instead. Check the inventory table too: the trap phone only works on an inventory that keeps item metadata.

Copying the item images

Copy the four .png files from items/ in the resource folder into your inventory's image folder:

  • ox_inventory: ox_inventory/web/images/
  • qb-inventory: qb-inventory/html/images/

The file names already match the item names, so no renaming is needed. Without an image the item still works; it just shows a blank picture.

Dirty money

Sales pay out as dirty money, and a robbery takes from the same place. By default (Framework dirty money) the script uses whatever your framework already ships:

FrameworkWhere the money goes
QBCoremarkedbills items. Each sale adds one bill with its worth written on it. A robbery takes bills, biggest first, and hands back change as a new bill
QBXblack_money items, worth $1 each. ox_inventory ships this item
ESXThe black_money account, which ESX ships

That works with no changes on a stock server. If your server keeps dirty money some other way, change General → Sale money in the settings menu to An account (and type the account name) or An item ($1 each) (and pick the item). See Configuration → General.

Database Setup

You don't need to do anything here. The first time oxide-drugselling starts, it creates its own tables through oxmysql.

sql/install.sql in the resource folder holds the same tables. You only need it if your database user isn't allowed to create tables. In that case, import it with your database tool before the first start.

TableWhat it stores
oxide_settingsYour live settings, edited in-game with /drugselling settings. Shared with other Oxide resources; each keeps its own rows
drugselling_heatHow much heat each area, corner, dealer and phone number has. Entries that haven't changed in 7 days are cleared when the resource starts
drugselling_phonesEvery trap phone: its number, PIN, first owner, reputation and battery
drugselling_clientsThe NPC clients in each phone's book, with their trust and what they remember
drugselling_messagesEvery text sent and received. Texts older than 30 days are cleared when the resource starts
drugselling_ordersClient orders and the meets booked for them
drugselling_dropsDead drop bags and cash waiting in the world, so they survive a restart

First-Time Setup In Game

1. Look over the settings

As an admin, run /drugselling settings. Almost every setting is in this menu, and changes apply the moment you save. See Admin → Permissions if it says you don't have permission.

The files in shared/config/ are the factory defaults: the values the resource starts from on its first launch. After that first start, the database holds your settings, and editing those files won't change most of them. Use the menu instead. See Configuration → How configuration is stored.

Worth checking first:

  • Core → Street → Police jobs: must match your police job names exactly. These jobs receive alerts and count toward Police needed online.
  • Pressure → Evidence → Jobs and Pressure → Stings → Jobs: the jobs that can read seized phones and use the sting phone.
  • Core → General → Sale money: see Dirty money.
  • Core → Street → Only on-duty police: on by default. If your police have no duty toggle and you use Police needed online, turn it off, or no officers will count.

2. Check the corner demand

Nothing needs placing: players start a corner wherever they stand with /corner or the radial menu. Run /drugselling corners and check the Demand list matches the drugs on your server (weed, meth, cocaine and pills ship). Drugs whose items don't exist are skipped automatically.

3. Check the dead drop spots

10 drop spots in south Los Santos ship by default. When a client books a dead drop, the spot nearest their home is used, however far away it is. If your players deal in other parts of the map, add spots there: run /drugselling drops, add a row under Drop spots, give it a name, press Place in world next to Spot, and save. With no spots at all, clients only offer hand-offs.

4. Decide how players get the items

Nothing in oxide-drugselling sells the phone items. Put them wherever fits your server:

  • trap_phone, trap_sim and trap_charger: a shop, a black-market dealer, a job reward. A phone bought from a shop or given with a give-item command is blank; it gets its own number the first time it's used.
  • sting_phone: give it to your police, for example in their armory.

The drug items themselves come from your drug resources (oxide-weed, oxide-meth, oxide-cocaine, oxide-pills) or from your own drugs added in shared/config/drugs.lua (see Configuration → Drugs).

Optional Integrations

Everything here is optional. oxide-drugselling runs without any of it.

ResourceWhat it addsWithout it
oxide-weedPlayers need weed level 2 to sell weed, and every sale gives weed XP. Strong strain traits add to the priceWeed sells at any level, with no XP and no trait bonus
oxide-methMeth sales give meth XP and count toward sold totalsMeth sells normally, with no XP
oxide-cocaineCocaine and crack sales give cocaine XP and count toward sold totalsCocaine and crack sell normally, with no XP
oxide-pillsEach buyer prices a pill by their own taste, the batch quality, how it's packed and the brand. Pill sales give pills XP and count toward sold totalsPills sell at their base price, with no XP. The server log shows one warning that the price export isn't running
oxide-gangsA gang territory's price and buyer settings change what buyers pay and how often they refuse. Sales build gang influence in that territoryPrices and refusals are unchanged
oxide-policeOfficers can attach a seized phone's contents to an MDT caseThe phone can still be read in-game; Send report says "No case system"
oxide-weatherThe server reads the in-game clock straight from itThe server asks a few players' games what time it is, once a minute
A dispatch resource o-link supportsPolice alerts go into your dispatch system, placed at the saleOfficers get a notification and a map blip at the sale

oxide-police

Seized-phone reports need an oxide-police version that includes the AttachCaseEvidence export. Version 1.9.0 and older don't have it. The bridge file is already in server/integrations/evidence/oxide_police.lua and switched on. The officer must be on duty, and the case number must belong to their department.

To connect a different MDT, see Evidence Bridge.

Verification

Start the server and watch the console. ox_lib, oxmysql, o-link and oxide-drugselling should start without errors, and you should see:

[INFO][oxide-drugselling][lifecycle] resource initialized

If you run oxide-logger, the line is written in its own format instead, like [oxide-drugselling][INFO] lifecycle: resource initialized, and also goes to its other log outputs.

Open the settings. Join, load a character, and run /drugselling settings. The settings menu should open.

Try a street sale. Give yourself a drug item from your drug resources (for example weed_1g with oxide-weed). Look at a pedestrian: Offer Drugs should appear. Pick it, and the pedestrian walks over and the sell menu opens with your item. Set a price the reaction meter shows as Good Deal and make the offer. Unless the buyer refuses (there's always a chance), the sale goes through. Then check the money arrived (see Dirty money).

Try the phone. Run /drugselling kit to get a trap phone, SIM, battery pack and sting phone. Use the Trap Phone item. The phone opens on your screen with its number on the home screen. Press Enter for the menu, and Contacts should list three starter clients. (Clients only order drugs whose items exist on your server, so a phone gets no clients if none of the shipped drugs are installed. See Troubleshooting.)

Wait for a text. Put the phone away (press Esc until it closes) and keep it on you. The first starter client answers at any hour and texts an order about 20 seconds after the phone is first used. Your phone rings and slides half up from the bottom of the screen to show the text. After that, clients only order during their own hours on the in-game clock.

Try a corner. Carry a drug from the corner Demand list (weed, meth, cocaine and pills ship), stand on foot anywhere and type /corner. You should see "You're working the corner. Buyers will come to you, so stay close to this spot." Within 25 to 70 seconds (faster or slower depending on the time of day) you get "Someone is approaching", and a buyer walks or drives up. Stand next to them and press E at the Deal prompt.

If any step fails, see Troubleshooting.

Good To Know

  • Keys or mouse. Arrow keys move, Enter selects, Backspace goes back, Esc goes back and closes the phone from the home screen, or click the phone's own keys. Players can walk (W A S D, Shift to run) with the phone open; no other key does anything while it's open. Players can bind a key to open their phone in Settings → Key Bindings → FiveM → Open trap phone (unbound by default).
  • The in-game clock matters. Clients answer and meets happen on the in-game clock, and the time of day changes how often corner buyers come and clients text. On a server with the standard GTA clock, one in-game hour passes in about two real minutes.
  • A phone belongs to its item, not to a character. Hand the phone to someone and the whole client book goes with it. A PIN keeps it locked for anyone else.
  • Translations: notifications, prompts, phone text and client messages are in locales/en.json.

Updating to 2.1.0

  • Upgrading from 2.0.0 needs no SQL or new inventory items. Existing saved settings remain.
  • shared/config/drugs.lua is file-only. If you customized it, merge the weed xpUnits values 1, 3, 6, 12, 24, 35 and weed progression.xpPerUnit = 10 yourself. Saved database settings do not apply this change. See Items.
  • Merge the new settings_ui_* keys into custom locales.
  • Restart oxide-drugselling after updating. If coming from 1.x, also follow the upgrade guide below.

Updating From 1.x

Version 2 moves settings into the database and adds the phone items, so an older install needs a few extra steps:

  1. Install oxmysql and update o-link to 1.9.1 or newer. In server.cfg, start both before oxide-drugselling.
  2. Register the four new items and copy their images (see Adding the items). The database tables are created on the first start.
  3. Replace your old config files with the new ones and copy your own edits across before the first start. After that, the files only fill in settings the database doesn't have yet — use /drugselling settings.
  4. Sale money now goes to your framework's dirty money by default. To keep paying sales in clean cash, set Config.DirtyMoney to mode = 'account', account = 'cash' before the first start.
  5. If your police have no duty toggle and you use Police needed online, turn off Only on-duty police, or no officers will count.
  6. If you translated locales/en.json, start again from the new file. Many keys were added and a few were removed.

Next Steps