Documentation

Config

Explanations for all config values.

General Information

The editable configuration is located in shared/unlocked/config.lua. Customer locations are configured separately in shared/unlocked/locations.lua.

Deal conversations and phone strings are translated in locales/en.lua, not in the config.

#Config.Settings

General resource settings that control how deals are generated, priced, and delivered.

#debug

Enables debug behavior for the resource. Only enable this in development environments because it exposes additional commands and diagnostics.

Example:

lua
debug = false

#blipsForLocations

Debug tool that places a map blip at every configured location so you can visualize their spread. With the amount of blips the resource spawns, you will hit the limit for text labels, so rely on the blip colors instead.

Example:

lua
blipsForLocations = false

#blipsForLocationCategory

The unique blip category used when blipsForLocations is enabled. The resource relies on a consistent category to group the blips, so you probably shouldn't touch this.

Example:

lua
blipsForLocationCategory = 168

#distanceFormat

The unit used when displaying the distance to a customer. Accepts "km" for kilometres or "mi" for miles.

Example:

lua
distanceFormat = "km"

#policeRequirement

The minimum amount of online police required before deals can be created. Set to 0 to disable the requirement.

Example:

lua
policeRequirement = 0

#policeJob

A list of jobs that count as police. Used for the police requirement and for alerting officers to ongoing deals. Add any additional police jobs your server uses.

Example:

lua
policeJob = {"police", "police2"}

#phoneModel

The prop model used for the phone when it is visible in the player's hand.

Example:

lua
phoneModel = "prop_prologue_phone"

#useZykeSounds

When true, phone sounds are played through zyke_sounds so nearby players can hear them. Requires zyke_sounds to be installed.

Example:

lua
useZykeSounds = true

#personalSettingsKey

The KVP key used to store per-player preferences such as UI scale, notifications, and location sync. Only change this if you want to reset everyone's saved preferences.

Example:

lua
personalSettingsKey = "zyke_drugdealer:settings"

#marketRateApp

Toggles the Market Rate app on the phone. The app shows how saturated the general area is and how generous the local buyers are, which helps you decide where to deal.

Example:

lua
marketRateApp = true

#allowShowOfferRange

Controls whether players are allowed to enable the offer range circles on their map. Players still have to enable the option themselves in their settings, and false force-disables it for everyone.

Example:

lua
allowShowOfferRange = true

#preferenceDecision

How likely (0-100%) a location's drug preference is used instead of picking a random drug. 100 always uses the location preferences for a more realistic, immersive experience, while 0 always picks a random drug for simpler gameplay with less strategy needed. Set to 0 by default to avoid confusion for first-time users.

Example:

lua
preferenceDecision = 0

#globalPriceMultiplier

A random multiplier range applied to all drug prices. A value between min and max is rolled with 2-decimal precision and applied on top of the price. Set both to 1.0 to disable the random variance.

Example:

lua
globalPriceMultiplier = {min = 0.90, max = 1.10}

#useLocationPricing

When true, each location's priceGenerosity value (configured in shared/unlocked/locations.lua) scales the price, so poorer areas pay less and richer areas pay more. When false, location generosity is ignored and flat pricing is used.

Example:

lua
useLocationPricing = true

Pricing Combinations

globalPriceMultiplier and useLocationPricing work together to decide how a deal price is calculated:

  • globalPriceMultiplier = {min = 1.0, max = 1.0}, useLocationPricing = true → Prices vary by location only, with no random variance.

  • globalPriceMultiplier = {min = 0.90, max = 1.10}, useLocationPricing = true → Location variance PLUS a ±10% random roll (stacks multiplicatively).

  • globalPriceMultiplier = {min = 0.80, max = 1.20}, useLocationPricing = false → Flat base price with a ±20% random variance and no location influence.

  • globalPriceMultiplier = {min = 1.0, max = 1.0}, useLocationPricing = false → Prices are exactly what's defined in the drug rewards table.

#status

Settings for how a player's phone preferences interact with a location's drug preferences. Players pick which drugs they want offers for in the Status app on the phone.

Example:

lua
status = {
    overridePreferences = true,
    acceleratedTimerDivisor = 5,
}

#status.overridePreferences

Controls whether a player's phone preferences override or filter the location's preferences.

  • true (Override mode): the player only gets offers for the drugs they selected, regardless of the area. Great for players who want to specialize in specific drugs.
  • false (Filter mode): the player only gets offers where both their preferences and the area's preferences match. This is the more strategic approach, but may result in fewer offers overall (possibly none), depending on the player's preferences and the area.

Set to true by default to avoid confusion for first-time users.

Example:

lua
overridePreferences = true

#status.acceleratedTimerDivisor

When a player's phone preferences don't match the area's preferences, the game tries to find a new offer faster by dividing the normal timer by this value. So if the timer is 60 seconds and this is 5, the retry happens after 12 seconds. Keeps the game flowing even when offers don't match.

Example:

lua
acceleratedTimerDivisor = 5

#policeAlert

Settings for alerting the police to drug deals, with separate chances, delays, and blips for failed and successful deals.

Example:

lua
policeAlert = {
    customDispatch = "",
    onFail = {
        callPoliceChance = 40,
        delay = {min = 5, max = 10},
        blipRadius = 100,
        blipLast = 30,
    },
    onSuccess = {
        callPoliceChance = 0,
        delay = {min = 5, max = 10},
        blipRadius = 100,
        blipLast = 30,
    },
}

#policeAlert.customDispatch

Identifier of a supported custom dispatch resource to handle police alerts. Supported values: "qs-dispatch". When using a custom dispatch, fill in the additional values that dispatch requires. Leave empty to use the default alert system.

Example:

lua
customDispatch = ""

#policeAlert.onFail

Settings applied when a deal fails, for example because the customer got frightened or cancelled.

Example:

lua
onFail = {
    callPoliceChance = 40,
    delay = {min = 5, max = 10},
    blipRadius = 100,
    blipLast = 30,
}

#policeAlert.onFail.callPoliceChance

Percentage chance that police are alerted when a deal fails. Set to 0 to disable. Has no effect once the offer has expired.

Example:

lua
callPoliceChance = 40

#policeAlert.onFail.delay

Delay before the police receive the notification, in seconds. A random value between min and max is chosen each time.

Example:

lua
delay = {min = 5, max = 10}

#policeAlert.onFail.blipRadius

Radius of the blip given to the police.

Example:

lua
blipRadius = 100

#policeAlert.onFail.blipLast

How long the blip stays on the map for the police, in seconds.

Example:

lua
blipLast = 30

#policeAlert.onSuccess

Settings applied when a deal completes successfully.

Example:

lua
onSuccess = {
    callPoliceChance = 0,
    delay = {min = 5, max = 10},
    blipRadius = 100,
    blipLast = 30,
}

#policeAlert.onSuccess.callPoliceChance

Percentage chance that police are alerted when a deal completes successfully. Set to 0 to disable.

Example:

lua
callPoliceChance = 0

#policeAlert.onSuccess.delay

Delay before the police receive the notification, in seconds. A random value between min and max is chosen each time.

Example:

lua
delay = {min = 5, max = 10}

#policeAlert.onSuccess.blipRadius

Radius of the blip given to the police.

Example:

lua
blipRadius = 100

#policeAlert.onSuccess.blipLast

How long the blip stays on the map for the police, in seconds.

Example:

lua
blipLast = 30

#smartSettings

A collection of smart features that react to suspicious player behaviour, such as cancelling the deal if you run or fight too close to the customer.

Example:

lua
smartSettings = {
    running = {
        range = 10,
        cancelDeal = false,
        policeAlertAddition = 20,
    },
    cancelIfFrightened = false,
    cancelIfInCombat = true,
    pedExistanceForAlert = 0,
    noItemsAddition = 20,
}

#smartSettings.running

Settings for detecting when the player runs close to the customer.

Example:

lua
running = {
    range = 10,
    cancelDeal = false,
    policeAlertAddition = 20,
}

#smartSettings.running.range

Set false/0 to disable, or an integer for how close you have to be for the running settings to take effect.

Example:

lua
range = 10

#smartSettings.running.cancelDeal

When true, the deal is cancelled if you run too close to the customer while range is enabled. You will receive a notification that your behaviour was suspicious and that the customer was no longer interested.

Example:

lua
cancelDeal = false

#smartSettings.running.policeAlertAddition

Percentage points added to the police alert chance if you're running close to the customer. Only applies when cancelDeal is disabled.

Example:

lua
policeAlertAddition = 20

#smartSettings.cancelIfFrightened

When true, the deal is cancelled if the customer ped is frightened, which includes you attacking it, aiming a weapon at it, and similar behaviour.

Example:

lua
cancelIfFrightened = false

#smartSettings.cancelIfInCombat

When true, the deal is cancelled if the customer ped is in combat, meaning it changes stance and tries to fight you.

Example:

lua
cancelIfInCombat = true

#smartSettings.pedExistanceForAlert

false/0 to disable, or a distance in which another ped has to be nearby for the police to be called if a deal is cancelled. Simulates realism, since someone actually has to be around to report it. Note that this only works if peds are enabled on your server, since they have to naturally walk or drive by.

Example:

lua
pedExistanceForAlert = 0

#smartSettings.noItemsAddition

Percentage points added to the chance that police are called if you don't have the items the customer wants.

Example:

lua
noItemsAddition = 20

#customerSettings

A collection of settings regarding customers and deal generation.

Example:

lua
customerSettings = {
    timeToFindCustomer = {min = 45, max = 90},
    timeBeforeOfferExpires = {min = 300, max = 600},
    timeBeforeCustomerLosesInterest = {min = 240, max = 480},
    cooldownForLocation = {min = 600, max = 1200},
    dealTime = {min = 6, max = 12},
    maxRangeForOffer = 1000,
    minRangeForOffer = 150,
    callToConfirm = true,
}

#customerSettings.timeToFindCustomer

Time, in seconds, before a new customer is found. A random value between min and max is chosen each cycle.

Example:

lua
timeToFindCustomer = {min = 45, max = 90}

#customerSettings.timeBeforeOfferExpires

How long, in seconds, an offer stays valid before it is automatically declined. A random value between min and max is chosen per offer.

Example:

lua
timeBeforeOfferExpires = {min = 300, max = 600}

#customerSettings.timeBeforeCustomerLosesInterest

If you accept an offer, this is how long, in seconds, you have to deliver the product before the customer loses interest. A random value between min and max is chosen per deal.

Example:

lua
timeBeforeCustomerLosesInterest = {min = 240, max = 480}

#customerSettings.cooldownForLocation

Cooldown, in seconds, before a location can generate another deal. This is not meant to lock locations away for hours; it simply stops people from AFK-ing superior locations and ruining the purpose of the script. A random value between min and max is chosen.

Example:

lua
cooldownForLocation = {min = 600, max = 1200}

#customerSettings.dealTime

How long, in seconds, the deal takes to complete (talking to the customer). A random value between min and max is chosen per deal.

Example:

lua
dealTime = {min = 6, max = 12}

#customerSettings.maxRangeForOffer

The maximum distance at which a location can generate an offer. Stops you from getting offers in Sandy Shores while you're in Grove Street.

Example:

lua
maxRangeForOffer = 1000

#customerSettings.minRangeForOffer

The minimum distance a location must be from you to generate an offer. Prevents offers spawning right next to each other, encouraging you to drive around and carry a bigger risk of being seen.

Example:

lua
minRangeForOffer = 150

#customerSettings.callToConfirm

When true, accepting an offer prompts a call with the customer to confirm. When false, the offer is accepted instantly when pressing the accept button.

Example:

lua
callToConfirm = true

#openPhone

A collection of ways to open the phone.

Example:

lua
openPhone = {
    item = "drugphone",
    command = {
        enabled = true,
        itemNeeded = true,
        name = "opendrugphone",
    },
    useItem = {
        enabled = true,
    },
    blockedJobs = {
        "police",
        "ambulance",
    },
}

#openPhone.item

The item needed to open the phone.

Example:

lua
item = "drugphone"

#openPhone.command

Settings for the command that opens the phone.

Example:

lua
command = {
    enabled = true,
    itemNeeded = true,
    name = "opendrugphone",
}

#openPhone.command.enabled

Toggles the command that opens the phone.

Example:

lua
enabled = true

#openPhone.command.itemNeeded

When true, the command only works if the player has the configured item in their inventory.

Example:

lua
itemNeeded = true

#openPhone.command.name

The name of the command that opens the phone.

Example:

lua
name = "opendrugphone"

#openPhone.useItem

Settings for opening the phone by using the item from your inventory.

Example:

lua
useItem = {
    enabled = true,
}

#openPhone.useItem.enabled

Toggles opening the phone by using the item (drag it to use in your inventory).

Example:

lua
enabled = true

#openPhone.blockedJobs

Jobs that are blocked from opening the phone. Add any job name to prevent those players from accessing it.

Example:

lua
blockedJobs = {
    "police",
    "ambulance",
}

#newCustomerAlert

Notifications when you get a new offer. If enabled here, each player can still toggle them individually in their phone settings; if disabled here, players can't enable them individually.

Example:

lua
newCustomerAlert = {
    notification = true,
    file = "message.mp3",
}

#newCustomerAlert.notification

Toggles the visual notification that appears when you get a new customer.

Example:

lua
notification = true

#newCustomerAlert.file

The audio file played as the notification sound when you get a new customer.

Example:

lua
file = "message.mp3"

#phoneCall

The audio clips played while talking to a customer on the phone. Add more audios into nui/talking/ and add them here; one is chosen randomly each call.

Example:

lua
phoneCall = {
    {file = "talking.mp3", cutAtLength = 5500},
    -- {file = "talking2.mp3", cutAtLength = 6000}, -- Slightly annoying audio, but you can enable it if you wish to have more than one
}

#phoneCall[x].file

The filename of the talking audio for this entry.

Example:

lua
file = "talking.mp3"

#phoneCall[x].cutAtLength

How long the call plays, in milliseconds. 5500 is 5.5 seconds.

Example:

lua
cutAtLength = 5500

#idleAnimations

Animations the customer plays while idling, before you start talking to them. When you talk to them, they look at you and transition into an animation from the animations list.

Example:

lua
idleAnimations = {
    {dict = "anim@amb@nightclub@peds@", anim = "rcmme_amanda1_stand_loop_cop"},
    {dict = "WORLD_HUMAN_STAND_IMPATIENT", anim = nil}, -- Scenario
}

#idleAnimations[x].dict

The animation dictionary for this idle animation. Use a scenario name such as WORLD_HUMAN_STAND_IMPATIENT with anim = nil to play a scenario instead.

Example:

lua
dict = "anim@amb@nightclub@peds@"

#idleAnimations[x].anim

The animation name for this idle entry. Set to nil when using a scenario as the dict.

Example:

lua
anim = "rcmme_amanda1_stand_loop_cop"

#animations

The animations customers use while talking to you. One is chosen randomly. Add as many as you want by following the format.

Example:

lua
animations = {
    {dict = "anim@amb@nightclub@peds@", anim = "rcmme_amanda1_stand_loop_cop"},
    {dict = "mp_missheist_countrybank@nervous", anim = "nervous_idle"},
}

#animations[x].dict

The animation dictionary for this animation.

Example:

lua
dict = "anim@amb@nightclub@peds@"

#animations[x].anim

The animation name for this entry. Set to nil with a scenario dict to play a scenario.

Example:

lua
anim = "rcmme_amanda1_stand_loop_cop"

#talkingAnim

The dictionary and animation used for your character when interacting with the customer.

Example:

lua
talkingAnim = {
    dict = "anim@amb@nightclub@peds@",
    anim = "rcmme_amanda1_stand_loop_cop",
}

#talkingAnim.dict

The animation dictionary for your character's talking animation.

Example:

lua
dict = "anim@amb@nightclub@peds@"

#talkingAnim.anim

The animation name for your character's talking animation.

Example:

lua
anim = "rcmme_amanda1_stand_loop_cop"

#events

The names of the client events the resource triggers throughout a deal. You normally won't need to touch these, but they can be changed to integrate with other resources. See Exports & Events for usage examples.

Example:

lua
events = {
    OfferDeclined = "zyke_drugdealer:OfferDeclined",
    OfferCreated = "zyke_drugdealer:OfferCreated",
    OfferExpired = "zyke_drugdealer:OfferExpired",
    OfferAccepted = "zyke_drugdealer:OfferAccepted",
    DealFinished = "zyke_drugdealer:DealFinished",
    DealCancelled = "zyke_drugdealer:DealCancelled",
}

#events.OfferDeclined

Triggered when you decline an offer.

Example:

lua
OfferDeclined = "zyke_drugdealer:OfferDeclined"

#events.OfferCreated

Triggered when a new offer is created and a message arrives on your phone.

Example:

lua
OfferCreated = "zyke_drugdealer:OfferCreated"

#events.OfferExpired

Triggered when an offer expires without being accepted.

Example:

lua
OfferExpired = "zyke_drugdealer:OfferExpired"

#events.OfferAccepted

Triggered when you accept an offer and receive the customer's location.

Example:

lua
OfferAccepted = "zyke_drugdealer:OfferAccepted"

#events.DealFinished

Triggered when the deal is completed and you sell your drugs.

Example:

lua
DealFinished = "zyke_drugdealer:DealFinished"

#events.DealCancelled

Triggered when a deal is cancelled, for example by suspicious behaviour or missing items.

Example:

lua
DealCancelled = "zyke_drugdealer:DealCancelled"

#logs

Toggles webhook logs for deal actions. The webhook itself is configured in the Logs function inside server/unlocked.lua.

Example:

lua
logs = {
    DealCreated = true,
    DealExpired = true,
    DealFinished = true,
    DealCancelled = true,
}

#logs.DealCreated

Logs when a new offer is created.

Example:

lua
DealCreated = true

#logs.DealExpired

Logs when an offer expires.

Example:

lua
DealExpired = true

#logs.DealFinished

Logs when a deal is completed.

Example:

lua
DealFinished = true

#logs.DealCancelled

Logs when a deal is cancelled.

Example:

lua
DealCancelled = true

#counterOffer

The negotiation system that lets you counter a customer's offer to squeeze out a better price. By default, a counter-offer re-rolls the price using the same logic as the original deal.

Example:

lua
counterOffer = {
    enabled = true,
    maxAttempts = 2, -- Max times player can counter-offer per deal
    skew = 0,
    responseDelay = {
        min = 10,
        max = 60,
    },
}

#counterOffer.enabled

Toggles the counter-offer system. When disabled, players can't negotiate and must accept the offer as-is.

Example:

lua
enabled = true

#counterOffer.maxAttempts

The maximum times a player can counter-offer on a single deal. Once the limit is reached, further counter-offers are blocked for that deal.

Example:

lua
maxAttempts = 2

#counterOffer.skew

A boost applied to the re-rolled price during a counter-offer. By default (skew = 0), counter-offers re-roll the price with the exact same logic as the original deal; if the new price is higher the customer accepts, otherwise they reject. A higher skew increases the chance of rolling a higher price and can exceed the original maximum price range.

  • skew = 0.1 means a +10% boost to the rolled price.
  • skew = 0.25 means a +25% boost (can exceed the original max price range).

Example: the original price was $50-$100 and you got $60.
With skew = 0, the re-roll is the $50-$100 range, so there's roughly a 40% chance to beat $60.
With skew = 0.2, the re-roll is effectively $60-$120, giving you a much higher chance.

Example:

lua
skew = 0

#counterOffer.responseDelay

The delay, in seconds, before the customer responds to a counter-offer. A random value between min and max is chosen per response.

Example:

lua
responseDelay = {
    min = 10,
    max = 60,
}

#reputation

The reputation system. Reputation affects pricing multipliers and changes based on your actions:

  • 0.0 = Terrible reputation (minimum)
  • 1.0 = Neutral (starting point)
  • 2.0 = Excellent (effective cap for multiplier benefits)
  • 5.0 = Maximum (provides a buffer against losses)

Reputation above 2.0 acts as a "safety buffer" - no extra pricing benefit, but room to absorb losses without falling below the effective cap.

Example:

lua
reputation = {
    enabled = false,
    onSuccess = 0.005,
    penalties = {
        lackItems = 0.010,
        lostInterest = 0.008,
        expired = 0.001,
        counterOfferDeclined = 0.003,
        playerDeclined = 0.0015,
    },
    defaultValue = 1.000,
    minValue = 0.000,
    maxValue = 5.000,
    effectiveCap = 2.000,
    buffs = {
        priceRoofCap = {
            enabled = true,
            bonus = {min = -0.15, max = 0.25},
        },
        quantityRoofCap = {
            enabled = true,
            bonus = {min = -0.40, max = 0.80},
        },
        policeAlertChance = {
            enabled = true,
            bonus = {min = -0.30, max = 0.50},
        },
    },
}

#reputation.enabled

Enables or disables the reputation system.

Example:

lua
enabled = false

#reputation.onSuccess

The reputation gained per successful sale.

Example:

lua
onSuccess = 0.005

#reputation.penalties

The reputation subtracted for failed or declined deal states. All values are positive numbers and will be subtracted.

Example:

lua
penalties = {
    lackItems = 0.010,
    lostInterest = 0.008,
    expired = 0.001,
    counterOfferDeclined = 0.003,
    playerDeclined = 0.0015,
}

#reputation.penalties.lackItems

Applied when the player didn't have enough drugs to complete the deal.

Example:

lua
lackItems = 0.010

#reputation.penalties.lostInterest

Applied when the customer waited too long and cancelled, including running or spooking them.

Example:

lua
lostInterest = 0.008

#reputation.penalties.expired

Applied when an offer expired without any player interaction. A minor penalty.

Example:

lua
expired = 0.001

#reputation.penalties.counterOfferDeclined

Applied when the customer rejects a player's counter-offer during negotiation.

Example:

lua
counterOfferDeclined = 0.003

#reputation.penalties.playerDeclined

Applied when the player manually declines an offer, choosing not to take the deal.

Example:

lua
playerDeclined = 0.0015

#reputation.defaultValue

The starting reputation for new players. 1.000 is the neutral baseline.

Example:

lua
defaultValue = 1.000

#reputation.minValue

The absolute floor for reputation. Reputation can't drop below this value.

Example:

lua
minValue = 0.000

#reputation.maxValue

The absolute ceiling for reputation. Reputation can't exceed this value regardless of gains.

Example:

lua
maxValue = 5.000

#reputation.effectiveCap

The effective cap used for multiplier calculations. Reputation above this provides a buffer but no extra pricing benefit.

Example:

lua
effectiveCap = 2.000

#reputation.buffs

Modular buffs that can each be enabled, disabled, and configured independently. Each buff uses asymmetric scaling: bonus.min is applied at the lowest effective reputation and bonus.max at the highest.

Example:

lua
buffs = {
    priceRoofCap = {
        enabled = true,
        bonus = {min = -0.15, max = 0.25},
    },
    quantityRoofCap = {
        enabled = true,
        bonus = {min = -0.40, max = 0.80},
    },
    policeAlertChance = {
        enabled = true,
        bonus = {min = -0.30, max = 0.50},
    },
}

#reputation.buffs.priceRoofCap

Affects the maximum (roof) of the price multiplier range. Only the roof changes; the floor stays the same.

Example with bonus = {min = -0.15, max = 0.25} and globalPriceMultiplier = {0.90, 1.10}:

  • Rep 0.0 → range becomes 0.90x - 0.93x (roof lowered by 15%)
  • Rep 1.0 → range stays 0.90x - 1.10x (no change)
  • Rep 2.0 → range becomes 0.90x - 1.37x (roof raised by 25%)

    Example:
lua
priceRoofCap = {
    enabled = true,
    bonus = {min = -0.15, max = 0.25},
}

#reputation.buffs.quantityRoofCap

Affects the maximum quantity customers request. Only the roof (max) changes; the floor stays the same.

Example with bonus = {min = -0.40, max = 0.80}:

  • Rep 0.0 → max quantity reduced by 40%
  • Rep 1.0 → no change
  • Rep 2.0 → max quantity increased by 80%

    Example:
lua
quantityRoofCap = {
    enabled = true,
    bonus = {min = -0.40, max = 0.80},
}

#reputation.buffs.policeAlertChance

A multiplier on the police call chance, applied as (1 - bonus), so a positive bonus means a lower chance. Low reputation increases the chance, high reputation decreases it.

Example with bonus = {min = -0.30, max = 0.50}:

  • Rep 0.0 → bonus = -0.30, multiplier = 1.30 (30% more police)
  • Rep 1.0 → bonus = 0, multiplier = 1.0 (no change)
  • Rep 2.0 → bonus = +0.50, multiplier = 0.50 (50% less police)

    Example:
lua
policeAlertChance = {
    enabled = true,
    bonus = {min = -0.30, max = 0.50},
}

#Config.Drugs

The list of drugs you can sell. Each entry defines the drug's label, inventory item, amount range, rewards, and optional props. The script comes pre-configured with examples to build from.

Example:

lua
Config.Drugs = {
    {
        label = "Weed",
        item = "weedleaf_quality2",
        drugAmount = {min = 1, max = 5},
        rewards = {
            {currency = "cash", amount = 10, chance = 100, multiplyWithAmount = true},
        },
        prop = {
            player = {
                model = "prop_meth_bag_01",
                bone = 28422,
                offset = {x = 0.05, y = 0.0, z = -0.02},
                rotation = {x = 0.0, y = 270.0, z = -20.0},
            },
            customer = {
                model = "prop_cs_cashenvelope",
                bone = 28422,
                offset = {x = 0.05, y = 0.0, z = -0.01},
                rotation = {x = 90.0, y = 150.0, z = 100.0},
            },
        },
    },
}

#Drugs[x].label

The label displayed for this drug in the phone messages.

Example:

lua
label = "Weed"

#Drugs[x].item

The inventory item sold, for example "weedleaf_quality2" or "cokeleaf_quality2".

Example:

lua
item = "weedleaf_quality2"

#Drugs[x].drugAmount

The amount of this drug the customer can ask for. A random amount between min and max is chosen per deal.

Example:

lua
drugAmount = {min = 1, max = 5}

#Drugs[x].rewards

The rewards granted for selling this drug. You can pay currency, give items, or a mix of both. Each reward has an amount, a selection chance, and whether it multiplies with the requested amount.

Example:

lua
rewards = {
    {currency = "cash", amount = 10, chance = 100, multiplyWithAmount = true},
    {item = "beer", amount = 1, chance = 20, multiplyWithAmount = true},
}

#Drugs[x].rewards[x].currency

The currency type paid, for example "cash" or "dirty_money". Use this OR item, not both. Whether a currency type is supported depends on your server.

Example:

lua
currency = "cash"

#Drugs[x].rewards[x].item

An item given as a reward instead of currency, for example "beer". Use this OR currency, not both.

Example:

lua
item = "beer"

#Drugs[x].rewards[x].amount

The amount paid, or items given, per unit the customer wants. With currency you can think of it as the price per gram.

Example:

lua
amount = 10

#Drugs[x].rewards[x].chance

The chance for this reward to be selected. Rewards are checked top to bottom and the chance caps at 100, meaning that if four rewards have a combined chance of 100, a fifth won't even be in the "raffle" to be selected.

Example:

lua
chance = 100

#Drugs[x].rewards[x].multiplyWithAmount

When true, the reward amount multiplies with the amount the customer wants. When false, the reward is a fixed amount regardless of the requested quantity - useful for rare items you don't want to hand out in bulk.

Example:

lua
multiplyWithAmount = true

#Drugs[x].prop

Optional props attached to the player and customer during the deal. Remove the whole table to disable props, or remove just one of the tables to disable them for that participant. The values can be tricky to get right, so we recommend using a prop placement tool to fine-tune models, bones, offsets, and rotations.

Example:

lua
prop = {
    player = {
        model = "prop_meth_bag_01",
        bone = 28422,
        offset = {x = 0.05, y = 0.0, z = -0.02},
        rotation = {x = 0.0, y = 270.0, z = -20.0},
    },
    customer = {
        model = "prop_cs_cashenvelope",
        bone = 28422,
        offset = {x = 0.05, y = 0.0, z = -0.01},
        rotation = {x = 90.0, y = 150.0, z = 100.0},
    },
}

#Drugs[x].prop.player

The prop attached to the player during the deal.

Example:

lua
player = {
    model = "prop_meth_bag_01",
    bone = 28422,
    offset = {x = 0.05, y = 0.0, z = -0.02},
    rotation = {x = 0.0, y = 270.0, z = -20.0},
}

#Drugs[x].prop.customer

The prop attached to the customer during the deal.

Example:

lua
customer = {
    model = "prop_cs_cashenvelope",
    bone = 28422,
    offset = {x = 0.05, y = 0.0, z = -0.01},
    rotation = {x = 90.0, y = 150.0, z = 100.0},
}

#Drugs[x].prop[x].model

The prop model, for both the player and customer. Find models here.

Example:

lua
model = "prop_meth_bag_01"

#Drugs[x].prop[x].bone

The bone the prop is attached to. Find bones here.

Example:

lua
bone = 28422

#Drugs[x].prop[x].offset

The position offset of the prop relative to the bone.

Example:

lua
offset = {x = 0.05, y = 0.0, z = -0.02}

#Drugs[x].prop[x].rotation

The rotation of the prop relative to the bone.

Example:

lua
rotation = {x = 0.0, y = 270.0, z = -20.0}

#Config.Locations

Locations are configured in a separate file, shared/unlocked/locations.lua, but are part of the config. Each location is a table with a spawn position, a price generosity, an optional drug preference, and the peds to spawn.

Example:

lua
Config.Locations = {
    {
        pos = vec(366.23, -1109.86, 29.40, 219.50),
        priceGenerosity = 1.1,
        drugPreference = {"cokeleaf_quality2"},
        peds = {"a_m_o_tramp_01", "a_m_o_soucent_03", "u_m_o_tramp_01"},
    },
}

#pos

The position where the customer spawns. Requires a vector4: vec4(x, y, z, w), where w is the heading.

Example:

lua
pos = vec(366.23, -1109.86, 29.40, 219.50)

#priceGenerosity

A price multiplier, with 1.0 being neutral. The script picks a random value between your value and 1, so 0.8 results in prices between 0.8x-1x (up to 20% below default) and 1.3 between 1x-1.3x (up to 30% above default). Set to 1.0 to keep the price default. Simulates realism, where poorer areas pay less and richer areas pay more for their fix. Only applies when useLocationPricing is enabled.

Example:

lua
priceGenerosity = 1.1

#drugPreference

The drugs customers in this area typically want, so different parts of the city want different drugs and create variety. Multiple preferences are supported. Remove the key or leave it empty to let customers want anything. Requires preferenceDecision and the location preference system to be in play.

Example:

lua
drugPreference = {"cokeleaf_quality2"}

#peds

The ped models spawned at this location. One is chosen at random for each customer.

Example:

lua
peds = {"a_m_o_tramp_01", "a_m_o_soucent_03", "u_m_o_tramp_01"}