npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

loot-table-advanced

v1.4.6

Published

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.

Downloads

98

Readme

Loot Tables Advanced

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.

alt text

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 crate_1 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.