API Reference

Server exports provided by oxide-pills — progression, XP and sales, buyer pricing through PriceFor, live settings — plus the metadata every pill item carries.

Server exports provided by oxide-pills, for developers integrating other resources (selling scripts, missions, leaderboards).

Any server resource can call these after oxide-pills has started.

Server Exports

GetPlayerLevel(source)

Returns the player's pill level (1–10 with the default level table).

local level = exports['oxide-pills']:GetPlayerLevel(source)

Returns 1 if the player has no character loaded. A character with no pill progression yet gets a level 1 row created.


GetPlayerProgression(source)

Returns the player's full pill progression stats.

local progression = exports['oxide-pills']:GetPlayerProgression(source)

Shape:

{
    level = 1,
    xp = 0,
    currentLevelXp = 0,      -- XP threshold of the current level
    nextLevelXp = 100,       -- XP threshold of the next level; nil at max level
    totalCreated = 0,        -- pills kept from sorted trays
    totalSold = 0,
    unlocks = {              -- stations, product lines and perks, ordered by level
        {
            level = 1,                -- the level it unlocks at
            label = 'Crank Press',    -- friendly name
            unlocked = true,          -- whether this player has reached it
        },
        -- ...
    },
}

Returns nil if the player's character identifier can't be found (for example, not fully loaded).


AddXP(source, amount)

Adds pill XP and runs the level-up check, so the player may level up from this call.

local ok = exports['oxide-pills']:AddXP(source, 25)

Parameters:

NameTypeDescription
sourcenumberThe player's server ID
amountnumberXP to add. Must be greater than zero.

Returns: boolean. true on success, false if the player has no character loaded or amount is missing, not a number, or not greater than zero.

oxide-drugselling calls this on every pill sale.


AddSold(source, amount)

Adds to the player's sold counter for pills, so sales show in /pills stats.

local ok = exports['oxide-pills']:AddSold(source, 12)

Returns: boolean, with the same rules as AddXP.

AddSold only updates the counter. It doesn't award XP (call AddXP too) and it doesn't build brand reputation. Brand reputation only grows from sales made through oxide-drugselling and from delivery run drops.


PriceFor(metadata, context)

The price multiplier a street buyer puts on a stack of pills. This is what oxide-drugselling calls (as an export_multiplier pricing modifier in its Config.Drugs.pills) to price every pill sale. It reads the batch's hidden stats on the server; the numbers never leave it.

local multiplier, details = exports['oxide-pills']:PriceFor(itemMetadata, { npcModel = GetEntityModel(buyerPed) })

Parameters:

NameTypeDescription
metadatatableThe pill item's metadata (it needs batch)
contexttableThe sale. npcModel (number, the buyer's model hash) decides which buyer type is buying.

Returns:

  • multiplier (number): multiply your base price by this. It's rounded to the nearest 0.05, so a price reads as good or bad without giving away the hidden stats. 1.0 when the item has no known batch, or when npcModel is missing or 0.
  • details (table or nil): one line for a sell panel, saying who the buyer is and what they thought. nil when the multiplier is the plain 1.0 fallback.
{
    {
        label = 'Club kid',              -- the buyer type
        value = 'Likes the faces',       -- what they thought
        bonus = 0.2,                     -- multiplier - 1.0
        color = 'text-emerald-400',      -- text-emerald-400 when they liked it, text-orange-400 when not
        type = 'variant',
    },
}

The multiplier includes the batch's quality, its packing, its product line, whether it's hot, and its brand's reputation. See Selling.


GetSetting(key)

Reads a live setting (the values stored in the oxide_settings table and edited from /pills settings; see Configuration). The key is the top-level config name without the Config. prefix.

local ownership = exports['oxide-pills']:GetSetting('RequireOwnership')
local delivery = exports['oxide-pills']:GetSetting('Delivery')   -- the whole Config.Delivery table

Returns: the current value (any type: boolean, number, string or table), or nil for an unknown key.


SetSetting(key, value)

Changes a live setting. It applies on the server straight away, is saved to the database, and is sent to every client. It's the same as saving it in the settings menu, and it lasts through restarts.

exports['oxide-pills']:SetSetting('RequireOwnership', false)

Parameters:

NameTypeDescription
keystringThe top-level config name without Config.
valueanyThe whole new value for that key. For a table like Delivery, pass the entire table.

Returns: true.

SetSetting doesn't check the value against the menu's limits the way the settings menu does, so pass a complete, valid value. Only use it for keys that appear in the settings menu. Skill and Buyers are meant to be read from the config file (see Configuration).

Prefer GetSetting/SetSetting over reading or writing the oxide_settings table directly. They keep the server, database and connected clients in sync in one call.

Item Metadata

Pill items carry metadata your scripts can read through your inventory's normal metadata access. The quality numbers are never in the metadata. They stay on the server, keyed by the batch ID, so they can't be read from an inventory. Use PriceFor if you need a batch's value.

Finished pills

party_pill, bar_pill, blue_pill, perc_pill, molly_capsule, and their packed items (bar_pill_bag, bar_pill_bottle, bar_pill_blister and so on; see Installation):

FieldDescription
batchThe batch ID. Every pill from one sorted tray shares it.
lineparty, bar, blues, perc or capsule
tintThe party pill colour (0–7)
stampThe face: plain (blank), ref (the line's reference imprint) or brand
brandThe brand's name, on branded party pills (public: it's on the face)
symbolThe brand's symbol, on branded party pills
descriptionThe batch's impression, for example "These look clean." For bottles and blisters, the label or card text too.
bagged1 when packed in a baggie
packed'bottle' or 'blister' when packed that way
labelThe bottle label template key, on bottled pills
coated1 on pan-coated pills
evidence1 once police have logged the stack as evidence

Pills of the same batch but different packing are separate items: loose pills are the base item, packed ones the line's packed item. The count is always tablets.

Other items

ItemMetadata fields
pill_milledgrind, fines, active (the raw active it came from), lot (mystery powder only), identified (after a reagent test), description
pill_blendformula, line, active, lot, activeRatio, binderRatio, lubeRatio, fillerRatio, grind, fines, uniformity, tint, granulation (after the sieve), tumbled (1 after the drum tumbler), description
punch_die_setwear, line (the shape it's cut for; none means party), stamp, brand (brand ID), serial (an opaque ID given the first time the die goes on a press, so the server can follow its wear), description
reagent_kituses (tests left), description
mystery_powderlot, identified (after a reagent test)
pill_rejectsline, lot

A mystery powder lot is an opaque ID. What it really is lives only on the server until a reagent test reveals it.

Integration Examples

Gate a feature behind pill level

local level = exports['oxide-pills']:GetPlayerLevel(source)
if level >= 5 then
    -- unlock a pharma wholesaler, a bigger stash, etc.
end

Price pills in your own selling script

-- Called from your sell handler with the pill's metadata and the buyer ped. The price is per
-- tablet, and a packed item prices as its loose line (PriceFor already weighs the packing).
local BASE_PRICE = { party = 30, capsule = 35, bar = 25, blues = 45, perc = 35 }

local function priceForPill(source, itemName, itemMetadata, buyerPed)
    local base = BASE_PRICE[(itemMetadata or {}).line] or 0
    local multiplier = exports['oxide-pills']:PriceFor(itemMetadata, { npcModel = GetEntityModel(buyerPed) })
    local price = math.floor(base * multiplier)

    -- ...remove the pill and pay the player through your framework here...

    -- Credit the sale to pill progression.
    exports['oxide-pills']:AddSold(source, 1)
    exports['oxide-pills']:AddXP(source, 3)
    return price
end

A custom selling script built this way prices pills the same way oxide-drugselling does, but it won't build brand reputation. Only oxide-drugselling sales and delivery drops do that.

Read a setting from another resource

local delivery = exports['oxide-pills']:GetSetting('Delivery')
if delivery and delivery.enabled then
    print(('Pill delivery runs pay $%d per VELA 30'):format(delivery.perTablet.blues))
end

Next Steps