Guide
Game loot tables and weighted random explained
Open a chest in an RPG, finish a raid boss, or pull a gacha banner — behind every reward screen is a loot table: a structured list of possible items, each with a weight or probability, sometimes gated by player level, kill count, or seasonal rules. Getting loot right shapes progression pacing, monetization trust, and whether players feel lucky or cheated. This guide explains how weighted random selection works in code, how rarity tiers and pity systems protect against streaks of bad luck, when rolls must run on the server, how to simulate and audit drop rates before launch, and how loot tables connect to the broader game economy.
What a loot table actually is
At minimum, a loot table is a collection of entries. Each entry specifies:
- Item reference — an ID pointing to stats, art, and stack rules in your item database.
- Weight or probability — how often this entry is chosen relative to siblings.
- Quantity range — e.g. 1–3 gold coins or exactly one sword.
- Conditions (optional) — only if player level > 20, only on first kill, only during Halloween event.
Tables are often nested. A boss might first roll on a table group (guaranteed vs bonus drop), then roll inside the chosen sub-table. A gacha banner might have separate pools for characters, weapons, and filler materials. Keeping this hierarchy in data files (JSON, CSV, ScriptableObjects) lets designers tune without recompiling.
The output of a roll is not always a single item. Many games roll N times (e.g. three independent picks from the same table) or roll once per rarity band (guaranteed rare + chance at epic). Document whether rolls are independent or mutually exclusive — players and economists will assume independence unless you say otherwise.
Weighted random: the algorithms
Given weights [10, 30, 60] for three items, you want item C roughly
60% of the time. Two standard approaches:
Cumulative distribution (roulette wheel)
Sum all weights (100), draw one uniform random integer or float in
[0, total), then walk the list subtracting weights until the remainder
goes negative. Simple, O(n) per roll — fine for small tables.
function pickWeighted(entries, rng) {
const total = entries.reduce((s, e) => s + e.weight, 0);
let roll = rng() * total;
for (const entry of entries) {
roll -= entry.weight;
if (roll < 0) return entry;
}
return entries[entries.length - 1];
}
Alias method
Preprocess weights into an alias table in O(n) setup time, then each draw is O(1). Worth it when you roll thousands of times per second (MMO mob farms, idle games) or run Monte Carlo simulations with millions of iterations.
Percent vs weight
Designers often think in percentages. Store weights as integers (1000 = common, 10 = legendary) rather than floats to avoid rounding drift. If entries must sum to exactly 100%, validate at build time and fail CI when a designer typo leaves a 99.7% table.
Never use Math.random() alone for security-sensitive or monetized
drops without a documented seed strategy. For cosmetic single-player loot it is
usually fine; for tradable items or real-money pulls, server authority is
mandatory (covered below).
Rarity tiers, buckets, and conditional tables
Most games group items into rarity bands — common, uncommon, rare, epic, legendary — each with its own sub-table. A two-stage roll first picks rarity (e.g. 70% common, 25% rare, 5% epic), then picks uniformly within that band. This keeps art pipelines organized and lets you rebalance one tier without touching others.
Conditional drops narrow the pool before the weight roll:
- Progression gates — no endgame gear below character level 40.
- First-time guarantees — tutorial chest always yields a useful weapon.
- Tag filters — frost enemies only roll from frost-tagged loot pools.
- Duplicate handling — if player already owns the skin, reroll or convert to shards.
Conditional logic belongs in a single loot resolver function so QA can log which filters fired. Scattering if-statements across gameplay code makes drop bugs nearly impossible to reproduce.
Pity, bad-luck protection, and soft guarantees
Pure independent rolls produce real streaks: a 1% legendary chance still means some players go 200 pulls without one. Pity systems cap frustration:
- Hard pity — after 90 pulls without a 5-star, the 91st is guaranteed.
- Soft pity — odds ramp from pull 75 onward until they hit 100% at 90.
- Bad-luck protection — increase weight slightly after each miss (reset on hit).
- Token systems — every pull grants a currency redeemable for a chosen item.
Pity state must persist server-side and survive client reinstalls. Store counters per banner, per account, and per pool if you run parallel events. When migrating pity between seasons, document whether counters reset — silent resets destroy trust.
Regulators in several regions require disclosed rates for paid random rewards. If you publish "0.6% legendary" but pity changes effective odds, the disclosed document must describe pity math or you risk misleading-advertising complaints.
Seeds, determinism, and procedural loot
Single-player games often tie drops to a world seed so speedrunners
and wiki writers can document fixed outcomes. Combine a master seed with encounter
IDs via a hash to get per-chest streams:
seed = hash(worldSeed, chestId). Our
procedural generation guide
covers seeded noise; the same discipline applies to loot streams.
Deterministic loot enables replay verification but breaks if you patch weights mid-save. Version your loot tables and either freeze seeds per save version or re-roll only for unopened containers.
For multiplayer, deterministic client rolls are an exploit vector. Treat client random as cosmetic preview only; the server sends the authoritative result.
Server-authoritative drops and anti-cheat
Any loot that can be traded, sold, or affects PvP power must be granted by the server after validating the triggering event (boss death, purchase receipt, quest completion). The typical flow:
- Client requests loot open with encounter proof (instance ID, signed timestamp).
- Server checks idempotency — this chest was not already opened.
- Server rolls using a CSPRNG, applies pity state, writes inventory grant.
- Client plays VFX; if packets drop, client reconciles from inventory snapshot.
Log every roll: account ID, table version, raw RNG output, pity counter before/after, and resulting item IDs. Logs support customer support tickets and fraud investigations. Patterns of identical rolls across accounts may indicate RNG seed reuse — a critical bug.
Online gambling-adjacent systems sometimes publish verifiable rolls (commit-reveal hashes). See provably fair game design for commit-reveal patterns; most RPG loot does not need on-chain proof, but the audit mindset is the same.
Testing drop rates with simulation
Before shipping a table, run Monte Carlo simulation: execute one million virtual rolls and compare empirical frequencies to design targets. A 5% epic drop should land near 50,000 ± statistical noise. Flag if results diverge more than a chosen confidence interval — usually a code bug or filter error.
Automate this in CI when loot JSON changes. Pair with property tests: pity never exceeds cap, empty tables fail fast, zero-weight entries never win, conditional gates never return out-of-band items.
Playtest sessions are too small to validate rare drops. Designers who "feel" rates are wrong after 50 pulls are reacting to variance, not proof. Simulation plus transparent in-game codex pages settle debates.
Live-service operations: seasons, tables, and rollback
Live games rotate loot pools weekly or seasonally. Treat each table as a versioned asset with effective start/end timestamps. When sunsetting an event pool, decide what happens to unredeemed tokens and in-progress pity — announce clearly in patch notes.
Hotfixing a table that is too generous is painful: players who received broken drops may need rollback, especially if items are tradeable. Prefer disabling a drop source over silently nerfing odds mid-event. For economy-wide inflation from overtuned tables, see sinks and tuning strategies in game economy design.
Tie rare drops to progression milestones so power curves stay predictable. A legendary weapon that doubles DPS at hour two collapses difficulty tuning and difficulty curves you spent weeks calibrating.
From roll to inventory
A loot roll is only half the pipeline. The grant must flow through your inventory system: stack limits, unique-equipped flags, soulbound rules, and overflow handling (mail queue vs destroy). Define behavior when the bag is full before the roll animation starts — nothing erodes trust faster than a VFX legendary that silently vanishes.
For MMO-scale drops, batch grants and defer UI fanfare until the server confirms persistence. Show a pending state if replication lags.
Production checklist
- Store tables as versioned data with build-time validation (weights > 0, sums correct).
- Centralize roll logic in one resolver with structured logging.
- Run Monte Carlo sims in CI for any table change affecting rare items.
- Keep pity and pull counters server-side with idempotent open requests.
- Publish drop rates (or in-game codex) wherever real money or tradable value is involved.
- Handle inventory overflow, duplicates, and conversion rules before playing VFX.
- Document season boundaries and pity resets in player-facing patch notes.
- Separate cosmetic preview RNG on clients from authoritative server grants.
Key takeaways
- Loot tables are structured data — items, weights, quantities, and conditions, often nested by rarity.
- Weighted random is easy to get subtly wrong — validate sums, use integer weights, simulate at scale.
- Pity and tokens manage variance — independent 1% rolls still feel brutal without a safety net.
- Server authority is non-negotiable for tradable or paid loot; log every roll.
- Economy and inventory are part of loot design — a drop is a currency injection with pacing consequences.
Related reading
- Game economy design explained — sources, sinks, and inflation control around random drops
- Game inventory systems explained — granting, stacking, and overflow after a roll
- Procedural generation in games explained — seeded worlds and deterministic loot streams
- Game player progression systems explained — pacing power gains from random rewards