Loot Tables are lists of items, quantities, and probabilities, used to create random outcomes for games. This Loot Table specification is both simple and expressive, able to power anything from random card packs to monster spawns to crate drops.

Stats

StarsIssuesVersionUpdatedCreatedSize
111.4.65 months ago2 years ago

Loot Tables are lists of items, quantities, and probabilities, used to create random outcomes for games. This Loot Table specification is both simple and expressive, able to power anything from random card packs to monster spawns to crate drops.

Loot Tables

Loot Tables have an ID, and a list of entries.

Loot Table Item type

The various Loot Table interfaces and functions take an optional generic type T that defaults to string. In your project, if you have an enum that defines valid item ids, you should supply that enum as your T parameter to preserve the typing throughout. The generic type V is used if you have a custom type for loot table ids.

Loot Table Entry

• `ItemID` or `@TableID` : T extends string
• `Min` : number - minimum quantity to produce
• `Max` : number - maximum quantity to produce
• `Step` : int - quantity will be in increments of this amount, or NaN for non-integer decimal values
• `Group` : int - entries may be grouped (see crate1 example below)
• `Weight` : int - the relative probability of for this entry
• `Transform` : function - optional transform

The optional transform function takes a number between 0.0 and 1.0 and should usually return a value between 0.0 and 1.0 as well. This can be used to do things like apply an easing function to the random number used to pick the value between Min and Max. The transformed value is not validated, so user beware. If you return a value below zero or above one, then you will get an output outside of your specified Min or Max.
Stupid Simple Example
This simple, one-item Loot Table will always produce "1 coin". The default value for all of the numeric properties is 1.
| ID | Weight | Min | Max | Step | Group | | ------ | ------ | --- | --- | ---- | ----- | | `coin` | 1 | 1 | 1 | 1 | 1 |

JavaScript

``````const simple = [ { id: 'coin' } ];
let loot = GetLoot(simple);``````

TypeScript

``````const simple: LootTable = [ { id: 'coin' } ]
let loot = GetLoot(simple)``````
Groups, nulls, and Quantities Example
This more complex Loot Table has two Groups. One entry will be chosen per Group to produce. Entries with a null ID produce nothing. Group 1 has a total weight of 14, so Group 1 has a 10-in-14 chance of producing from the coin entry. If the coin entry is selected, it will produce 50, 75, or 100 units of coin, due to how Min, Max, and Step are specified. Group 2 has a total weight of 10, and since cloth and null both have a weight of 5, there's a 50/50 chance that Group 2 will produce nothing. If the cloth entry is selected, it will produce 40, 45, or 50 units of cloth. Overall, this Loot Table may produce nothing at all, some coin, some cloth, or some of both.
| ID | Weight | Min | Max | Step | Group | | ------- | ------ | --- | --- | ---- | ----- | | `coin` | 10 | 50 | 100 | 25 | 1 | | `null` | 4 | 0 | 0 | 1 | 1 | | `cloth` | 5 | 40 | 50 | 5 | 2 | | `null` | 5 | 0 | 0 | 1 | 2 |
The code examples show the use of the `LootTableEntry` helper function, which performs error checking on the inputs and returns a valid object.

JavaScript

``````const crate_1 = [
LootTableEntry('coin', 10, 50, 100, 25, 1),
LootTableEntry(null, 4, 1, 1, 1, 1),
LootTableEntry('wood', 5, 40, 50, 5, 2),
LootTableEntry(null, 5, 1, 1, 1, 2),
];
let loot = GetLoot(crate_1);``````

TypeScript

``````const crate_1: LootTable = [
LootTableEntry('coin', 10, 50, 100, 25, 1),
LootTableEntry(null, 4, 1, 1, 1, 1),
LootTableEntry('wood', 5, 40, 50, 5, 2),
LootTableEntry(null, 5, 1, 1, 1, 2),
]
let loot = GetLoot(crate_1)``````
Nested Loot Tables
A Loot Table Entry may specify an Item ID, as in the examples above, or an Entry may specify the ID of another Loot Table to generate items from. The only restriction is that Loot Table references may not create a circular reference. To differentiate Item ID from Loot Table ID, an `@` character is used to prefix the Loot Table IDs.

gems and treasure example

`gems`

| ID | Weight | Min | Max | Step | Group | | ---------- | ------ | --- | --- | ---- | ----- | | `pearl` | 1 | 5 | 10 | 1 | 1 | | `garnet` | 1 | 3 | 12 | 1 | 1 | | `ruby` | 1 | 4 | 9 | 1 | 1 | | `sapphire` | 1 | 1 | 2 | 1 | 1 |

`treasure`

| ID | Weight | Min | Max | Step | Group | | ------- | ------ | --- | --- | ---- | ----- | | `@gems` | 1 | 0 | 2 | 1 | 1 | | `gold` | 1 | 15 | 20 | 1 | 2 |
The `treasure` Loot Table will always give you 15 to 20 gold, and zero, one, or two results from the `gems` table.

JavaScript

``````const gems = [
LootTableEntry('pearl', 1, 5, 10, 1, 1),
LootTableEntry('garnet', 1, 3, 12, 1, 1),
LootTableEntry('ruby', 1, 4, 9, 1, 1),
LootTableEntry('sapphire', 1, 1, 2, 1, 1),
];
const treasure = [
LootTableEntry('@gems', 1, 0, 2, 1, 1),
LootTableEntry('gold', 1, 15, 20, 1, 2),
];
function ResolveHelper(id) {
switch (id) {
case 'gems':
return gems;
case 'treasure':
return treasure;
}
return null;
}
let loot = GetLoot(treasure, 1, ResolveHelper);``````

TypeScript

``````const gems: LootTable = [
LootTableEntry('pearl', 1, 5, 10, 1, 1),
LootTableEntry('garnet', 1, 3, 12, 1, 1),
LootTableEntry('ruby', 1, 4, 9, 1, 1),
LootTableEntry('sapphire', 1, 1, 2, 1, 1),
]

const treasure: LootTable = [
LootTableEntry('@gems', 1, 0, 2, 1, 1),
LootTableEntry('gold', 1, 15, 20, 1, 2),
]

function ResolveHelper(id: string): LootTable | null {
switch (id) {
case 'gems':
return gems
case 'treasure':
return treasure
}
return null
}

let loot = GetLoot(treasure, 1, ResolveHelper)``````
Multiple Items Without Replacement
To simulate something like, "draw two cards", where you can't get the same item twice, the Loot Table Advanced `GetLoot` allows the caller to specify a `count`. The count defaults to 1. Pass in a count of 2 or more, and the Loot Table will be processed multiple times, each time decrementing the Weight of the entry selected.
| ID | Weight | Min | Max | Step | Group | | ----- | ------ | --- | --- | ---- | ----- | | ace | 1 | 1 | 1 | 1 | 1 | | king | 1 | 1 | 1 | 1 | 1 | | queen | 1 | 1 | 1 | 1 | 1 | | jack | 1 | 1 | 1 | 1 | 1 |
`GetLoot('cards',2)` will get two distinct cards, since the Weight of each card in the table is 1. Within the one call, each time a random entry is selected, it's Weight is decremented, preventing it from being selected again. `GetLoot('cards_chips')` will yield between 10 and 50 chips, in multiples of 5, and 2 unique cards from the cards table.

JavaScript

``````const cards = [
LootTableEntry('ace'),
LootTableEntry('king'),
LootTableEntry('queen'),
LootTableEntry('jack'),
];
const cards_chips = [
LootTableEntry('chips', 1, 10, 50, 5, 1),
LootTableEntry('@cards(2)', 1, 1, 1, 1, 2),
];
let loot = GetLoot(cards_chips, 1, (id) => (id == 'cards' ? cards : null));``````

TypeScript

``````const cards: LootTable = [
LootTableEntry('ace'),
LootTableEntry('king'),
LootTableEntry('queen'),
LootTableEntry('jack'),
]
const cards_chips: LootTable = [
LootTableEntry('chips', 1, 10, 50, 5, 1),
LootTableEntry('@cards(2)', 1, 1, 1, 1, 2),
]
let loot = GetLoot(cards_chips, 1, (id) => (id == 'cards' ? cards : null))``````

To reference another Loot Table, and specify a count, follow the `@id` with the count in parenthesis `(n)`, for example: `@cards(2)`
Summarize a Loot Table
With nested loot tables, and data-driven design, it can be hard to tell what might a given loot table yield. To get a flattened summary of a loot table, with just the `id`, `min`, and `max` properties, but no nested references, there is a helper function called `LootTableSummaryAsync`.
Call LootTableSummaryAsync to see what the possible yields are from a loot table. The concept of multiple draws without replacement is not taken into account. The summarization process basically combines groups by taking the smallest min and largest max of the group, then sums mins and maxes across groups.