Configuration

Detailed configuration reference for all Oxide Vending config files.

config/config.lua

General settings for the resource.

Bridge Settings

-- Override framework auto-detection
-- nil = auto-detect, 'qbcore' = force QBCore, 'esx' = force ESX, 'standalone' = force standalone
Config.BridgeOverride = nil

-- Standalone money system functions (only used when bridge is 'standalone')
-- Server owners must implement these to connect to their money system.
Config.StandaloneMoney = {
    Get = function(source, moneyType) return 0 end,
    Add = function(source, moneyType, amount, reason) return false end,
    Remove = function(source, moneyType, amount, reason) return false end,
}

-- Standalone inventory system functions (only used when bridge is 'standalone')
-- Server owners must implement these to connect to their inventory system.
Config.StandaloneInventory = {
    GetItemList = function() return {} end,
    AddItem = function(source, item, amount) return false end,
    RemoveItem = function(source, item, amount) return false end,
    GetItem = function(source, item) return nil end,
    GetInventoryItems = function(source) return {} end,
    CanCarryItem = function(source, item, amount) return true end,
}

Debug Mode

Config.Debug = false  -- Enable verbose console logging

Banking Integration

Config.UseBanking = true                      -- Use oxide-banking (false = QB money system)
Config.BusinessAccountPrefix = 'vending-'     -- Account name prefix

Business Settings

Config.Business = {
    MaxMachinesPerBusiness = 10,    -- Base limit (overridden by progression)
    MaxEmployees = 5,               -- Base limit (overridden by progression)
    RegistrationFee = 5000,         -- Cost to register a business
    AllowMultipleBusinesses = false, -- Can a player own multiple businesses?
    OnePerAccount = false,           -- Restrict to one business per account (across all characters)
    DefaultMachineCapacity = 400,   -- Fallback capacity when machine type is unknown
}

Permissions

Config.Permissions = {
    owner = { 'manage', 'stock', 'collect', 'place', 'remove', 'hire', 'fire', 'pricing', 'withdraw', 'deposit', 'view_balance' },
    manage = { 'stock', 'collect', 'place', 'remove', 'pricing', 'deposit', 'view_balance' },
    collect = { 'collect', 'view_balance' },
    stock = { 'stock' },
}

Placement Settings

Config.Placement = {
    MaxDistanceFromPlayer = 10.0,     -- Maximum distance to place machine from player
    MinDistanceBetweenMachines = 2.0, -- Minimum distance between machines
    FollowOffset = 1.2,               -- Distance in front of player during positioning
    RotationSensitivity = 5.0,        -- Mouse rotation speed in rotation mode
}

Blocked Zones

Config.BlockedZones = {
    -- { name = 'police_station', coords = vector3(x, y, z), radius = 50.0 },
}

Pricing Settings

Config.Pricing = {
    MinMarkup = 0.8,                -- Minimum price = 80% of base price
    MaxMarkup = 3.0,                -- Maximum price = 300% of base price
    DefaultMarkup = 1.5,            -- Default price = 150% of base price
}

Wholesale Settings

Config.Wholesale = {
    Enabled = true,
    MarkupPercent = 0.20,           -- 20% markup on wholesale orders
    DeliveryTime = 300,             -- Seconds until delivery (0 = instant)
    MinOrder = 10,                  -- Minimum quantity per order
    DeliveryCheckInterval = 30,     -- How often to check for pending deliveries
}

Warehouse Settings

Config.Warehouse = {
    Enabled = true,
    Price = 50000,                  -- Purchase price for warehouse
    MaxCapacity = 5000,             -- Maximum total items
    MaxItemTypes = 50,              -- Maximum different item types
    RequiredLevel = 3,              -- Business level required
    CodeLength = 4,                 -- Access code digit length
    DoorLocation = vector4(-128.68, -1393.47, 28.59, 208.25),
    Interior = {
        Exit = vector4(1087.57, -3099.38, -39.0, 264.61),
        Storage = vector4(1100.98, -3101.89, -39.0, 183.82),
    },
    BucketIdStart = 1000,
}

Pickup Location Settings

Config.PickupLocation = {
    Enabled = true,
    Coords = vector4(-128.35, -1416.47, 30.3, 114.55),
    PalletModel = 'bkr_prop_coke_pallet_01a',
    BoxModel = 'prop_cs_cardbox_01',
    MaxBoxes = 12,
    PickupTime = 3000,              -- Progress bar duration (ms)
    PickupAnimation = {
        dict = 'anim@amb@nightclub@mini@drinking@drinking_shots@ped_a@drunk@heeled@',
        anim = 'pickup',
    },
}

Transaction Pruning

Config.Transactions = {
    RetentionDays = 90,             -- How long to keep transactions (0 = forever)
    PruneInterval = 3600,           -- How often to run pruning (seconds)
    PruneOnStartup = true,          -- Run pruning when resource starts
}

Showroom Settings

Config.Showroom = {
    Enabled = true,
    Location = vector3(-132.5, -1418.28, 31.3),
    Heading = 208.38,
    Blip = {
        enabled = true,
        sprite = 478,
        color = 2,
        scale = 0.7,
        label = 'Vending Machines',
    },
    NPC = {
        model = 's_m_m_lifeinvad_01',
        scenario = 'WORLD_HUMAN_CLIPBOARD',
    },
}

Notifications

Config.Notifications = {
    Position = 'top-right',
    Duration = 5000,
}

Interaction Settings

Config.Interaction = {
    TargetDistance = 2.5,           -- qb-target interaction distance
    UseProgressbar = true,
    StockingTime = 3000,            -- Time to stock items (ms)
    CollectTime = 2000,             -- Time to collect revenue (ms)
}

Durability Settings

Config.Durability = {
    Enabled = true,
    DegradationPerSale = 0.5,           -- Durability lost per player sale
    DegradationPerNPCSale = 0.3,        -- Durability lost per NPC sale
    BrokenThreshold = 0,                -- Machine breaks at this durability
    WarningThreshold = 20,              -- Warning when durability below this
    RepairCosts = {
        drinks = 500,
        snacks = 400,
        general = 750,
        electronics = 1500,
    },
    DefaultRepairCost = 500,
    AllowCollectWhenBroken = true,
    DegradationVariance = 0.2,          -- +/- 20% variance
}

config/machines.lua

Machine type definitions.

Machine Types

Config.MachineTypes = {
    drinks = {
        label = 'Drink Machine',
        description = 'Sells beverages and drinks',
        price = 15000,              -- Purchase price
        slots = 8,                  -- Number of item slots
        capacity = 50,              -- Max items per slot
        models = {
            { model = 'prop_vend_soda_02', label = 'Sprunk Machine' },
            { model = 'prop_vend_soda_01', label = 'eCola Machine' },
            { model = 'prop_vend_fridge01', label = 'Fridge' },
            { model = 'prop_vend_water_01', label = 'Water Cooler' },
            { model = 'prop_vend_coffe_01', label = 'Coffee Machine' },
        },
        icon = 'fas fa-glass-water',
    },
    snacks = {
        label = 'Snack Machine',
        description = 'Sells food and snacks',
        price = 12000,
        slots = 6,
        capacity = 40,
        models = {
            { model = 'prop_vend_snak_01', label = 'Snack Dispenser' },
            { model = 'prop_vend_snak_01_tu', label = 'Snack Dispenser (Alt)' },
        },
        icon = 'fas fa-cookie-bite',
    },
    general = {
        label = 'General Vendor',
        description = 'Sells various items',
        price = 20000,
        slots = 12,
        capacity = 30,
        models = {
            { model = 'prop_vend_fags_01', label = 'Cigarette Machine' },
        },
        icon = 'fas fa-store',
    },
    electronics = {
        label = 'Electronics Kiosk',
        description = 'Sells phones and electronics',
        price = 35000,
        slots = 6,
        capacity = 20,
        models = {
            { model = 'prop_vend_soda_01', label = 'Electronics Kiosk' },
        },
        icon = 'fas fa-mobile-alt',
    },
}

Adding a New Machine Type

  1. Add to Config.MachineTypes:
newtype = {
    label = 'Display Name',
    description = 'Description',
    price = 25000,
    slots = 8,
    capacity = 50,
    models = {
        { model = 'prop_name', label = 'Model Label' },
    },
    icon = 'fas fa-icon',
}
  1. Add item whitelist in config/items.lua
  2. Add wholesale catalog in config/wholesale.lua
  3. Add NPC type modifier in config/npc_sales.lua

config/items.lua

Item whitelists and base prices.

Item Whitelists

Config.ItemWhitelists = {
    drinks = {
        'water_bottle',
        'coffee',
        'kurkakola',
        'grapejuice',
    },
    snacks = {
        'bread',
        'tosti',
        'twerks_candy',
        'sandwich',
        'chimpschips',
        'snikkel_candy',
    },
    general = {
        'lighter',
        'rolling_paper',
        'water_bottle',
        'bandage',
        'painkillers',
        'phone',
    },
    electronics = {
        'phone',
        'radio',
        'tablet',
        'laptop',
        'fitbit',
        'cryptostick',
        'electronickit',
        'gps',
        'binoculars',
    },
}

Base Prices

Config.ItemBasePrices = {
    -- Drinks
    water_bottle = 5,
    coffee = 8,
    kurkakola = 6,
    grapejuice = 7,

    -- Snacks
    tosti = 10,
    twerks_candy = 4,
    sandwich = 15,
    chimpschips = 8,
    snikkel_candy = 4,

    -- General
    lighter = 5,
    rolling_paper = 3,
    painkillers = 100,
    phone = 500,

    -- Electronics
    radio = 100,
    tablet = 300,
    laptop = 800,
    fitbit = 150,
    cryptostick = 200,
    electronickit = 250,
    gps = 75,
    binoculars = 50,
}

Adding New Items

  1. Ensure item exists in your framework's item registry (e.g. qb-core/shared/items.lua for QBCore, ox_inventory item config for ox_inventory, or your ESX items table)
  2. Add to appropriate whitelist in Config.ItemWhitelists
  3. Add base price to Config.ItemBasePrices
  4. Optionally add wholesale entry in config/wholesale.lua

config/wholesale.lua

Bulk ordering catalog.

Config.WholesaleCatalog = {
    drinks = {
        { item = 'water_bottle', basePrice = 3, minQty = 10, label = 'Water Bottle' },
        { item = 'coffee', basePrice = 5, minQty = 10, label = 'Coffee' },
        { item = 'kurkakola', basePrice = 4, minQty = 15, label = 'Kurkakola' },
        { item = 'grapejuice', basePrice = 4, minQty = 15, label = 'Grape Juice' },
    },
    snacks = {
        { item = 'tosti', basePrice = 6, minQty = 10, label = 'Tosti' },
        { item = 'twerks_candy', basePrice = 2, minQty = 25, label = 'Twerks Candy' },
        { item = 'sandwich', basePrice = 8, minQty = 10, label = 'Sandwich' },
        { item = 'chimpschips', basePrice = 4, minQty = 20, label = 'Chimps Chips' },
        { item = 'snikkel_candy', basePrice = 2, minQty = 25, label = 'Snikkel Candy' },
    },
    general = {
        { item = 'lighter', basePrice = 2, minQty = 20, label = 'Lighter' },
        { item = 'rolling_paper', basePrice = 1, minQty = 30, label = 'Rolling Paper' },
        { item = 'water_bottle', basePrice = 3, minQty = 10, label = 'Water Bottle' },
        { item = 'bandage', basePrice = 30, minQty = 10, label = 'Bandage' },
        { item = 'painkillers', basePrice = 60, minQty = 5, label = 'Painkillers' },
        { item = 'phone', basePrice = 300, minQty = 3, label = 'Phone' },
    },
    electronics = {
        { item = 'phone', basePrice = 300, minQty = 3, label = 'Phone' },
        { item = 'radio', basePrice = 60, minQty = 5, label = 'Radio' },
        { item = 'tablet', basePrice = 180, minQty = 3, label = 'Tablet' },
        { item = 'laptop', basePrice = 500, minQty = 2, label = 'Laptop' },
        { item = 'fitbit', basePrice = 90, minQty = 5, label = 'Fitbit' },
        { item = 'cryptostick', basePrice = 120, minQty = 5, label = 'Crypto Stick' },
        { item = 'electronickit', basePrice = 150, minQty = 5, label = 'Electronic Kit' },
        { item = 'gps', basePrice = 40, minQty = 5, label = 'GPS' },
        { item = 'binoculars', basePrice = 30, minQty = 5, label = 'Binoculars' },
    },
}

config/npc_sales.lua

NPC sales simulation settings. See NPC Sales for detailed explanation.

Core Settings

Config.NPCSales = {
    Enabled = true,
    TickInterval = 60,              -- Seconds between simulation ticks
    BaseChancePerTick = 0.05,       -- 5% base chance per machine per tick
    MinQuantity = 1,
    MaxQuantity = 2,
    AvoidLastItem = true,           -- Don't buy last item in slot
    PreferCheaperItems = true,
    RevenueMultiplier = 1.0,
    DefaultLocationMultiplier = 1.0,

    VisualFeedback = {
        Enabled = true,             -- Animate ambient peds when NPC sales occur
        PlayerRange = 50.0,         -- Player must be within this distance
        PedSearchRadius = 30.0,     -- Search radius for ambient peds
        MachineCooldown = 30000,    -- Cooldown per machine in ms
    },
}

Machine Type Modifiers

MachineTypeModifiers = {
    drinks = 1.5,       -- High velocity
    snacks = 1.3,       -- Frequent purchases
    general = 0.8,      -- Occasional
    electronics = 0.4,  -- Rare
},

Time Multipliers

TimeMultipliers = {
    [0]  = 0.2,     -- Midnight
    [7]  = 1.0,     -- Morning commute
    [8]  = 1.3,     -- Rush hour
    [12] = 1.5,     -- Lunch rush
    [17] = 1.4,     -- Evening commute
    [23] = 0.3,     -- Late night
    -- ... all 24 hours defined
},

Hotzones

Hotzones = {
    {
        name = 'legion_square',
        coords = vector3(195.0, -935.0, 30.0),
        radius = 150.0,
        multiplier = 2.5,
    },
    -- More zones...
},

Competition Settings

Config.Competition = {
    Enabled = true,
    Radius = 500.0,                     -- Competition radius in meters
    SameOwnerCompetes = false,          -- Same-business machines don't compete
    MinMultiplier = 0.3,                -- Floor for competition penalty
    MaxMultiplier = 1.8,                -- Ceiling for competition bonus
    CheapestBonus = 1.5,                -- Bonus when you have cheapest price
    SuggestedPriceMargin = 0.95,        -- Suggest price at 95% of competitor average
    SuggestedPriceMinMarkup = 0.85,     -- Don't suggest below 85% of base price
    AnalysisCacheTime = 300,            -- Seconds to cache competition analysis
    ShowCompetitorNames = true,         -- Display competitor business names
    ShowExactPrices = true,             -- Show exact competitor prices
}

config/progression.lua

Progression system settings. See Progression for detailed explanation.

Level Definitions

Config.Progression = {
    Enabled = true,
    Levels = {
        [1] = {
            name = 'Newcomer',
            xpThreshold = 0,
            revenueMilestone = 0,
            rewards = {
                maxMachines = 3,
                maxEmployees = 1,
                unlockedTypes = { 'drinks' },
                pricingRange = { min = 0.9, max = 1.5 },
                wholesaleDiscount = 0,
                npcRevenueBoost = 0,
            },
        },
        -- Levels 2-10...
    },
}

XP Sources

XPSources = {
    playerSale = 10,
    npcSale = 5,
    salePerDollar = 0.1,
    stockItems = 3,
    stockPerItem = 0.5,
    collectRevenue = 5,
    collectPerDollar = 0.02,
    hireEmployee = 50,
    placeMachine = 100,
    wholesaleOrder = 15,
    repairMachine = 20,
    dailyLoginBase = 25,
    dailyStreakBonus = 5,
    dailyStreakMax = 7,
},

Milestone Bonuses

Milestones = {
    { id = 'revenue_1k', type = 'revenue', value = 1000, xp = 100, label = 'First $1,000' },
    { id = 'sales_100', type = 'sales', value = 100, xp = 150, label = '100 Sales' },
    { id = 'machines_3', type = 'machines', value = 3, xp = 150, label = '3 Machines' },
    { id = 'employees_first', type = 'employees', value = 1, xp = 100, label = 'First Employee' },
    -- More milestones...
},