🎰 Loot Tables
Weighted random drops with nested table support, variable amounts, and unique-per-roll guarantees.
Defining a Loot Table
Register loot tables via the Convex defineLootTable mutation. Each table has weighted entries that can drop items, currencies, nothing, or reference nested tables.
typescript
await ctx.runMutation(api.economyLootTables.defineLootTable, {
gameId,
tableId: "boss_dragon_table",
name: "Dragon Boss Drops",
rollCount: 3, // Roll 3 times per drop
unique: true, // No duplicate entries per roll
entries: [
{ type: "item", id: "dragon_scale", amount: 1, weight: 30 },
{ type: "currency", id: "gold", amountMin: 100, amountMax: 500, weight: 50 },
{ type: "item", id: "legendary_staff", amount: 1, weight: 2 },
{ type: "nothing", weight: 18 },
],
});Entry Fields
| Field | Type | Description |
|---|---|---|
type | 'item' | 'currency' | 'nothing' | What this entry drops |
id | string | Item ID or currency ID (not needed for 'nothing') |
weight | number | Relative weight (higher = more likely) |
amount | number | Fixed drop amount |
amountMin / amountMax | number | Random amount range (used instead of fixed amount) |
nestedTableId | string | Roll another table instead of dropping directly |
Table Options
| Field | Type | Description |
|---|---|---|
rollCount | number | How many times to roll (default 1) |
unique | boolean | If true, each entry can only be picked once per roll |
Rolling a Table
Use POST /loot/roll. The system rolls the table, grants all results to the player, and records a loot transaction.
bash
curl -X POST https://gameplaygen.com/api/economy/loot/roll \
-H "Authorization: Bearer gg_live_sk_..." \
-H "Content-Type: application/json" \
-d '{
"gameId": "j97abc...",
"playerId": "j97def...",
"tableId": "boss_dragon_table"
}'json
{
"success": true,
"data": {
"results": [
{ "type": "item", "id": "dragon_scale", "amount": 1 },
{ "type": "currency", "id": "gold", "amount": 347 },
{ "type": "item", "id": "dragon_scale", "amount": 1 }
]
}
}Nested Tables
An entry can reference another loot table via nestedTableId. When that entry is rolled, the referenced table is rolled instead. Nesting is capped at 5 levels to prevent infinite loops.
typescript
// Sub-table for rare materials
await ctx.runMutation(api.economyLootTables.defineLootTable, {
gameId,
tableId: "rare_materials",
name: "Rare Materials",
entries: [
{ type: "item", id: "mithril_ore", amount: 1, weight: 40 },
{ type: "item", id: "dragon_heart", amount: 1, weight: 10 },
{ type: "item", id: "phoenix_feather", amount: 1, weight: 5 },
],
});
// Main table references the sub-table
{
type: "nothing", // type is ignored for nested
weight: 15,
nestedTableId: "rare_materials",
}Variable Amounts
Use amountMin and amountMax instead of amount for randomized quantities. The actual amount is uniformly distributed between min and max (inclusive).