Adding a Case

This page is the hands-on cookbook for adding a brand-new case to your server. You'll register a case item in your inventory, define its loot table in config.lua, and learn how to balance weights and add custom rarities.

The recipe has three parts:

  1. Register the case item in your inventory's items file (per-inventory snippets below)
  2. Define the loot table in Config.Cases in config.lua
  3. Restart the resource and test

1. Register the Case Item

Pick the section that matches your inventory.

ox_inventory

In ox_inventory/data/items.lua:

['premium_case'] = {
    label = 'Premium Case',
    weight = 100,
    stack = true,
    close = true,
    description = 'A premium case with high-tier rewards.',
    client = {
        export = 'legends_cases.openCase',
    },
},

The client.export field tells ox_inventory to call the legends_cases.openCase client export when the player uses the item. No additional Lua wiring needed.

qb-inventory

In qb-core/shared/items.lua:

['premium_case'] = {
    name = 'premium_case',
    label = 'Premium Case',
    weight = 100,
    type = 'item',
    image = 'premium_case.png',
    unique = false,
    useable = true,
    shouldClose = true,
    combinable = nil,
    description = 'A premium case with high-tier rewards.'
},

legends_cases registers the case as usable via QBCore.Functions.CreateUseableItem automatically — set useable = true and you're done.

qs-inventory / codem-inventory / origen_inventory / tgiann-inventory / ps-inventory

Add the item to your inventory's items file with useable = true (or the equivalent flag — check your inventory's documentation). The bridge handles registration through the inventory's standard usable-item callback.

ESX legacy

In es_extended/locales/<lang>.lua (or wherever your server defines items), add the item with usable = 1:

INSERT INTO `items` (`name`, `label`, `limit`, `rare`, `can_remove`)
VALUES ('premium_case', 'Premium Case', 50, 0, 1);

The bridge calls ESX.RegisterUsableItem('premium_case', ...) automatically when the resource starts.

The case item key (e.g., 'premium_case') must match exactly the key you'll use in Config.Cases in the next step.

2. Define the Loot Table

Open config.lua and add an entry to Config.Cases:

Config.Cases = {
    ['premium_case'] = {
        label = 'Premium Case',
        items = {
            -- Common (high weight)
            { item = 'bandage',          count = 10, chance = 60.0, rarity = 'milspec'    },
            { item = 'water',            count =  5, chance = 50.0, rarity = 'milspec'    },
 
            -- Uncommon
            { item = 'lockpick',         count =  3, chance = 30.0, rarity = 'restricted' },
            { item = 'phone',            count =  1, chance = 20.0, rarity = 'restricted' },
 
            -- Rare
            { item = 'WEAPON_STUNGUN',   count =  1, chance =  8.0, rarity = 'classified' },
            { item = 'armor',            count =  3, chance =  6.0, rarity = 'classified' },
 
            -- Very rare
            { item = 'WEAPON_PISTOL',    count =  1, chance =  3.0, rarity = 'covert'     },
 
            -- Jackpot
            { item = 'WEAPON_COMBATPDW', count =  1, chance =  0.5, rarity = 'gold'       },
        },
    },
}

Per-item field reference

FieldTypeNotes
itemstringInventory item name (consumables, weapons, custom items, cash items — anything your inventory recognizes)
countnumberQuantity awarded when this slot wins
chancenumberWeight — see balancing section below. Higher = more likely. Does NOT need to sum to 100 across the table
raritystringKey from shared/rarities.lua — drives the color of this slot on the reel

3. Restart and Test

ensure legends_cases

Or live-reload:

restart legends_cases

Give yourself a case (admin command examples):

# ox_inventory
/giveitem [your_id] premium_case 1

# qb-inventory
/giveitem [your_id] premium_case 1

# ESX legacy
/giveitem [your_id] premium_case 1

Use the case from your inventory. The roulette wheel should appear, spin for Config.SpinDuration ms, and award a weighted random reward.


Balancing Weights

chance values are weights, not percentages. The probability of any slot is chance / sum(all chances).

Example

{ item = 'A', count = 1, chance = 50.0, rarity = 'milspec'    },  -- 50/80 = 62.5%
{ item = 'B', count = 1, chance = 25.0, rarity = 'restricted' },  -- 25/80 = 31.25%
{ item = 'C', count = 1, chance =  4.0, rarity = 'covert'     },  --  4/80 =  5%
{ item = 'D', count = 1, chance =  1.0, rarity = 'gold'       },  --  1/80 =  1.25%
-- Sum: 80

To make item D twice as likely without recalculating everything else, just bump it to chance = 2.0. The new sum becomes 81 and the percentages adjust automatically.

A useful balancing pattern: assign weights like 60 / 25 / 10 / 4 / 1 for milspec / restricted / classified / covert / gold respectively. That gives roughly 60% / 25% / 10% / 4% / 1% odds and is easy to remember.

Picking a winning slot

The server uses a weighted random algorithm: roll r = random(0, sum), walk the table accumulating weights, the slot whose accumulated weight first exceeds r wins. The roulette reel is then built so the visual win index lands on that slot, and the spin animation stops there.


Custom Rarities

Want a "Knife" tier with a unique color? Edit shared/rarities.lua:

Rarities = {
    milspec    = { color = '#4b69ff', label = 'Mil-Spec' },
    restricted = { color = '#8847ff', label = 'Restricted' },
    classified = { color = '#d32ce6', label = 'Classified' },
    covert     = { color = '#eb4b4b', label = 'Covert' },
    gold       = { color = '#ffd700', label = 'Gold' },
 
    -- Add your own
    knife      = { color = '#e4ae39', label = 'Knife' },
    foil       = { color = '#00ffff', label = 'Foil' },
}

Then reference it in any case entry:

{ item = 'WEAPON_KNIFE', count = 1, chance = 0.1, rarity = 'knife' },

The reel and reveal modal will pick up the new color automatically. No React rebuild required — the rarity table is read at runtime.


Common Patterns

Daily login crate (mostly common, never empty)

['daily_crate'] = {
    label = 'Daily Crate',
    items = {
        { item = 'bandage',  count = 3, chance = 70.0, rarity = 'milspec'    },
        { item = 'water',    count = 5, chance = 60.0, rarity = 'milspec'    },
        { item = 'lockpick', count = 1, chance = 15.0, rarity = 'restricted' },
        { item = 'cash',     count = 500, chance = 5.0, rarity = 'classified' },
    },
},

Premium / store crate (small chance at top-tier weapons)

['premium_crate'] = {
    label = 'Premium Crate',
    items = {
        { item = 'WEAPON_PISTOL',     count = 1, chance = 30.0, rarity = 'restricted' },
        { item = 'WEAPON_SMG',        count = 1, chance = 15.0, rarity = 'classified' },
        { item = 'WEAPON_ASSAULTRIFLE', count = 1, chance = 5.0, rarity = 'covert' },
        { item = 'WEAPON_HEAVYSNIPER', count = 1, chance = 0.5, rarity = 'gold' },
    },
},

Cash crate (every roll wins money, just different amounts)

['cash_crate'] = {
    label = 'Cash Crate',
    items = {
        { item = 'cash', count =   100, chance = 60.0, rarity = 'milspec'    },
        { item = 'cash', count =   500, chance = 25.0, rarity = 'restricted' },
        { item = 'cash', count =  2500, chance =  8.0, rarity = 'classified' },
        { item = 'cash', count = 10000, chance =  2.0, rarity = 'covert'     },
        { item = 'cash', count = 50000, chance =  0.2, rarity = 'gold'       },
    },
},
⚠️

The cash item name varies by framework. ox_inventory expects money, qb-core uses cash and bank, ESX uses money. Check your server's items file.

Need help? Join our Discord (opens in a new tab) and open a support ticket!


Legends Store - Premium FiveM Scripts