> For the complete documentation index, see [llms.txt](https://infinitypbr.gitbook.io/magic-pig-games/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://infinitypbr.gitbook.io/magic-pig-games/game-modules-4/module-documentation/loot/custom-loot-generation-algorithm.md).

# Custom Loot Generation Algorithm

As development on your project progresses, you may wish to augment the chances a player has of discovering specific loot, or higher quality loot. To do this, you'll likely want to adjust the loot generation algorithm. The **Party Based RPG demo game** demo scene has an example of this, in the "Lucky" treasure box.

{% hint style="info" %}
In my own game, "*Legend of the Stones*", players will have a "*Luck*" `Stat`, and I want this value to affect the chances loot being spawned and of `ItemAttributes` being added to spawned loot.
{% endhint %}

In the demo, notice that *Lucky Treasure Box* has a new component which *Small Treasure Box* does not have. The `GenerateItemModificaitonDemo.cs` script is where the custom code lives. Open that up to check it out. It implements `IHandleLootBoxes`. (If you'd like, duplicate this script to make your own version!

<figure><img src="/files/Nv6qcUj0ZMRDOv1ayubR" alt=""><figcaption></figcaption></figure>

For the purposes of the demo, I've included a slider for a `float luckValue`, valued between `0.1f` and `1f`.  I started by copying the following methods from LootBox.cs into this new script:

* `GenerateItems()`
* `SpawnChance()`
* `GenerateAttributes()`

And I created a new method, `PlayerIsLucky()`, which returns true if a random `float` value between `0f` and `1f` is less than the set `luckValue`.

The methods were modified in only a few places, to take into account whether the `PlayerIsLucky()`.&#x20;

```csharp
// ORIGINAL
if (spawnChance < 1f && RandomFloat() > spawnChance) // If a random value is > our chances, do not spawn
{
     .....

// LUCKY VERSION
var spawnChance = SpawnChance(i, totalItemsToSpawn, itemsSetting); // Compute spawn chancesif (spawnChance < 1f 
     && (PlayerIsLucky() ? RandomFloatBestOf() : RandomFloat()) > spawnChance // If a random value is > our chances, do not spawn
{
     .....
```

The original version, if the `spawnChance` is not 100%, checks to see if a `RandomFloat()` -- a value between `0f` and `1f` -- is greater than the `spawnChance`. If true, it means we will not spawn the item. If `stopAfterFirstFailure` is `true`, then we will `return` the current list of `generatedItems`, otherwise we'll continue, and the script will move on to the next potential item.

The modified version first only checks random values if `spawnChance` is not 100%, like the original. If the `PlayerIsLucky()`, then the script will return a `float` value using the method `RandomFloatBestOf(false)`, which will give the lower of two random `float` values between `0f` and `1f`. Otherwise, the script will act as the original does, with a single `float`.&#x20;

In essence this gives a lucky player a slightly better chance of having the item spawned. There are similar modifications to the other methods. Have a look at the code to see those changes.

{% hint style="success" %}
`RandomFloatBestOf()` is a method in the `Utilities` class, under the `InfinityPBR.Modules` namespace. The default options are to provide the higher value of two rolls between `0f` and `1f`. However, you can adjust the number of rolls, the min and max values, as well as whether higher is better.

For example, this code will provide the highest value between `1f` and `10f`, out of 4 random value rolls.

`RandomFloatBestOf(true, 4, 1f, 10f);`
{% endhint %}

## How does this custom code get used?

`GameLootBox.cs` has this field, which will take in an `IHandleLootBoxes` component, such as `GenerateItemModificaitonDemo.cs` , which is populated on `Awake()`. As long as a script which implements `IHandleLootBoxes` is attached to the same object as `GameLootBox`, it will be used here.

{% code title="GameLootBox.cs" %}

```csharp
private IHandleLootBoxes _customLootBoxHandler;

private void Awake()
{
     _customLootBoxHandler = GetComponent<IHandleLootBoxes>();
}
```

{% endcode %}

When `GenerateLoot()` is called, it will pass along `IHandleLootBoxes`, which may be `null`, or may be popualted with a custom script.

{% code title="GameLootBox.cs" %}

```csharp
public void GenerateLoot(bool overwrite = true)
{
     if (!overwrite && _generated) return;
     itemObjectList = LootBox.GenerateLoot(_customLootBoxHandler).Clone(); 
     _generated = true;
            
     HandleLoot();
}
```

{% endcode %}

The `LootBox` Scriptable Object is used to compute the final items generated with the method `GenerateItems()`. However, if the handler is not null, it will call `handler.GenerateItems()` instead.

{% code title="LootBox.cs" %}

```csharp
public virtual GameItemObjectList GenerateLoot(IHandleLootBoxes handler)
{
     GameItemObjectList newList = new GameItemObjectList();
     if (handler != null)
     {
          newList.list.AddRange(itemsSettings.SelectMany(handler.GenerateItems).ToList());
     }
     else
     {
          newList.list.AddRange(itemsSettings.SelectMany(GenerateItems).ToList());
     }
     return newList;
}
```

{% endcode %}
