Skip to main content

ARPG Loot Generation

Prerequisites

This guide assumes you have a basic knowledge of the plugin:

  1. How to create a new Loot Table Template.
  2. How to use the Loot Registry Subsystem.
  3. How to use float masks.

Example

See LV_UseCases in the example map for an implementation. All loot tables use the Loot Registry system; to see the loot tables, click on the STLootRegistrationComponent on each trigger actor.


Overview

Action Role Playing Game (ARPG) Loot Generation involves generating items which have multiple parts:

  • The Base Item Type, e.g., a piece of armor like 'Leather Hood'.
  • The Rarity, e.g., 'Normal', 'Magical', or 'Rare'. Many ARPGs also include 'Unique', but we won't cover that in this guide.
  • The Affixes, e.g., '30% increased power'.

We can generate each of these parts using a separate loot table for each one.

info

The items generated by this example do not affect gameplay, nor do they have a fully backing item system. They are only for demonstrating Stoch's loot tables.

note

For the purposes of this demo, we assume a specific ARPG Loot System used by several popular ARPGs. However, Stoch can be used for nearly any loot system.

Preparing Data

First we'll prepare all of the data we need for the generation process.

Base Item Type

For the base item type, we have created the data table named DT_Armor. This includes a set of demo item types:

And the corresponding loot table, named LT_Armor. This Loot Table Template uses an Unlimited distribution type.

Masks

For this table, we will want to limit which items can drop based on the area's level. To prepare for this, we will add a Copy Data Mask Generator; this will copy the Item Level property from each data table row:

Rarity

Rarity determines the number of affixes an item can have. The demo assumes affixes are split into two types: prefixes and suffixes. This Loot Table Template also uses an Unlimited distribution type.

RarityPrefix/Suffix CountTotal affixes
Normal0 / 00
Magical1 / 12
Rare3 / 36

Masks

Many ARPG games offer 'Increased Magic Find', or increasing the chances for rolling magical and rare items. To prepare for this, we will add a mask generator for MagicFindEffect that stores how increases to magic find should affect each row's weight:

Affixes

For the affixes, we first create a data table for each type of affix:

We create a loot table template for each 'affix group'. Affix groups are affixes that have the same effect (e.g., 'Increased Power'), but different tiers (e.g., +11-20%, +21-30%, +31-40%). Each of these tiers are mutually exclusive. Here's one of the loot tables for an affix group:

Then we will include all of the groups in a loot table template:

Organizing the affixes into smaller loot table templates helps when we have multiple loot tables that use them. For example, suppose we want to have different affix possibilities for Swords and Maces. But these two weapon types share most of the same affixes (e.g., they both have 'Health', 'Strength', etc., but maybe swords have 'Increased Slashing Damage' and maces have 'Increased Smashing Damage'). Instead of referencing the affixes data table directly from each loot table, we create smaller loot tables so we can mix-and-match which affix groups we want for swords and maces.

Masks

We will use float masks to ensure:

  • We limit the number of prefixes and suffixes.
  • Affixes within groups are mutually exclusive.

To prepare for this, we will add a Bool Comparison mask generator to evaluate whether each row is a prefix or a suffix:

We will also add a Gameplay Tag Enumerate mask generator to create masks for each affix group:

Generation

Now that we have all of the data tables and loot tables created, we can write the generation process.

The process for each item will go like this:

  1. Roll a base item type, limiting based on the item level.
  2. Roll a random rarity, affected by magic find.
  3. Create a float mask (AffixesMask) which represents changes to affix weights. It will start with 1.0 for each row (all default weights).
  4. Optionally, scale the weights of specific affixes (see section below).
  5. Roll AffixCount between MinAffixCount and MaxAffixCount based on our rolled rarity.
  6. Roll affixes up to AffixCount:
    1. Masked sample from the affixes loot table by multiplying AffixesMask.
    2. Update how many prefixes/suffixes we have based on the sampled affix. If we reach our limit, remove them from AffixesMask.
    3. Remove all affixes in our sampled affix's group from AffixesMask.
note

This process is fully implemented in the BP_SampleAffixedItems blueprint in the example map.

Roll Base Item Type

We get the ItemLevel float mask from the LT_Armor loot table, then call Filter <= to filter out all rows with item level greater than our area's item level. For example:

IndexMask (Item Level)Mask (Filter <= 20)
011.0
1101.0
2201.0
3400.0

Multiplying the loot table's weights by this mask effectively filters out rows with item level greater than 20.

Roll Rarity

We get the MagicFindEffect float mask from the LT_Rarity loot table, then:

  1. Multiply by the player's magic find (negative to reduce magic find, positive to increase magic find, 0 has no effect).
  2. Add 1.0 so it can be multiplied to the loot table's weights.
  3. Masked sample and Multiply the magic find mask.

Here's how the mask changes:

Zero Magic Find (+0%)

RarityOriginal WeightMask (Magic Find Effect)Mask (After Multiply)Mask (After Adding 1)Final WeightProbability
Normal10,000-0.30.01.010,00050.0%
Magical7,0000.70.01.07,00035.0%
Rare3,0001.30.01.03,00015.0%

Increased Magic Find (+50%)

RarityOriginal WeightMask (Magic Find Effect)Mask (After Multiply)Mask (After Adding 1)Final WeightProbability
Normal10,000-0.3-0.150.858,50038.0%
Magical7,0000.70.351.359,55041.5%
Rare3,0001.30.651.654,95021.5%

Reduced Magic Find (-50%)

RarityOriginal WeightMask (Magic Find Effect)Mask (After Multiply)Mask (After Adding 1)Final WeightProbability
Normal10,000-0.30.151.1511,50067.3%
Magical7,0000.7-0.350.354,55026.6%
Rare3,0001.3-0.650.651,0506.1%

note

You can tune the Magic Find Effect to whatever values you want. We opted for these values because they behave similarly to how most players would expect.

Roll Affixes

First, we create a AffixesMask which will be reused when rolling all affixes for the item. We initialize it to 1.0 for all rows; since we're multiplying the mask, this doesn't change weights at all:

Next, using the rarity we rolled earlier, we roll the affix count for this item; it should be between Rarity:MinAffixCount and Rarity:MaxAffixCount. The maximum number of allowed prefixes/suffixes will be half of Rarity:MaxAffixCount:

Then, we roll each affix:

  1. Masked Sample by multiplying our AffixesMask. Remember, our AffixesMask holds the cumulative filters for this item's rolled affixes.
  2. Roll a random magnitude within our affix's range (e.g., for the +11-20% tier, we find a random value in the range: 11%, 15%, etc.):

  1. Update our prefix and suffix counts for this item:

  1. If we reached the prefix or suffix limit, filter them from our AffixesMask:

  1. Filter all affixes in our sampled affix's group:

For example, if we rolled Power3, our tag would be Affix.Group.Power. We find the mask for Affix.Group.Power, which includes all rows in this group. We invert the filter, so it excludes all affixes in this group instead. Then we multiply it to our AffixesMask to ensure this group isn't eligible for subsequent affix rolls:

AffixOriginal WeightMask (Affix.Group.Power)Mask (Inverted)Final Weight
Power33001.00.00
Int33000.01.0300
Dex33000.01.0300

Addendum: Scaling Affix Weights

Some games want to modify affix weights for specific crafting methods. You can do this by scaling the initial AffixMask:

We convert the filtering mask for an affix group (e.g., Affix.Group.Power) to a scaling mask for those rows. This modifies filtered rows' weights, but keeps the other rows the same. It looks like this:

AffixOriginal WeightMask (Affix.Group.Power)Mask (ScaleFilter 1.5)Final Weight
Power33001.01.5450
Int33000.01.0300
Dex33000.01.0300

Addendum: Boss Affixes

Some games may want to add special affixes to the pool for items dropped by bosses, or for other reasons. In this case, we recommend composing loot table templates and their masks, then using the same generation method above. For example, our item's basic loot table contains the default affixes, then we can append the boss's affix loot table to the end.

Results

When displayed in a widget, here is what a random item might look like: