Confusing Enemy drop Scriptable Object

I’d like to have some help. I want to add some comments to my code since I’m really confused as to what exactly each of these means.

I am having a hard time understanding what exactly is it doing from my example:
the Item is a BOW.
Relative chance - bow being drop?
Min number - of bow to drop?
Max number - of bow to drop?

Drop Chance Percentage - total chance of the enemy having a drop?
Min drops - min number of total drops?
max drops - max number of total drops?

what’s the differences of element 0 from element 1?
sorry I’m confused. need help. thank you.

1 Like

We’ll start with Drop Chance Percentage, you have that exactly correct. It’s the chance from 1-100 that any items will drop at all. The number of drops will be between MinDrops[leve] and MaxDrops[level], but be aware that Random.Range(1,2) will always return 1 because Random.Range always returns max-1.

Now on to the Potential dorps. For each drop, we’re assigning the number of chances. Think of these chances like raffle tickets. Supposing that there are 10 chances to get the bow, and 10 chances to get the Necklace. This effectively means that there’s a 50/50 (50%) chance to get either… now suppose ou wanted the Necklace to be a rare drop while the bow is a common drop… You could do this by changing the relative chance on the necklace to 1… now there’s a 1/11 (9%) chance of getting the necklace.
Like the Drop Chance Percentage, you need to set the min and max number for each level (as well as the relative chance for each level) or the system isn’t going to work properly.

1 Like

Okay, I get it now That potential drops work like in diablo2.
can you confirm if my understanding is correct?

  • so each item’s Relative Chance value will be divided by the total relative chances of all the items.
    it’s 10 out of 20 in my example of getting the bow. a 50/50 chance.

  • Min Number / Max Number is how many items can drop. so in my example I still need to put 1 in Min Number element0 to work properly?

  • the Drop Chance percentage is the chance of the enemy will be dropping something or not. 100% in my example.

  • Min Drop / Max Drop is how many items can the enemy drop.

So the element0 is level 1, element1 = level2, element2 = level3 and so on.
is this correct? I’m confused with this elements.

Thank you.

The elements represent the value at each level. This lets you set different values for each level…
For example, in the beginning, you might want to drop a Rusty Sword of Adequate Sufficiency, as this is an expected drop from a level 1 character. So in the early levels (elements), you might set a high chance of getting this item… say 50 tickets, when everything else has 10 tickets…
But as you increase in level, players might not be as happy filling their inventory with beginner items, so you might have a Well Polished Sword of Improved Damage, which you probably don’t want the player to get early on in the game. So as you set things up for each level, you’re going to want to reduce the Rusty Sword value down to 1 chance or zero, and then increase the chance for the Well Polished sword, maybe even setting it at 0 for the first 5 levels, and then start adding chances there, so maybe by level 20, it’s 100 tickets.

On Non-stackable items (equipment!), I would always set the Minimum drop and Maximum Drop to 1 at every level. You don’t want to drop two Ragged Leather Jerkin of Barely Noticable Protection from the same enemy, as the enemy would likely only be wearing one such Jerkin. For stackable items (Potions!) you would start with 1 at each level and then increase the Max as the levels increase.

1 Like

Thank you for clarifying that.
So if on a piece of equipment the min and max drop needed to be set to 1 to prevent multiple drops of the same item.
Does this mean that an enemy can not have like for example = dropping 1 other type of item let’s say a potion and the other an equipment at the same time?
since in this situation, I will have to put a max drop of 2 to be able to have a possibility of dropping both at the same time. 1 a potion and 1 an equipment.

Is this doable? how can I handle something like multiple equipment drops from a single enemy like a boss for example?


The section in red details the statistics on an individual item. In this case, Gold pieces (we’ll cover those in more detail in Shops and Abilities). There is a high probability of Gold pieces being in the drops, as it gets 20 relative chances while the Wooden Dagger gets 1 chance. The min at level 1 is 16 and the max at level 1 is 23. On the dagger, the min is 1 and max is 1, which is what you want if it’s not stackable.

The section is blue is the overall percentage of dropping anything at all. This is what determines how many drops you’ll get, in this case set to 1 and 1, but you could set that second number higher and you would have the chance to get more drops.

For a Boss, I would have another drop library with increased numbers and percentages.

This is quite conflicting for me so I need to set max drops to 1 to prevent duplicated items being dropped at the same time.

yet on the other post, it’s alright to increase the max drops since it handles the amount of drops a single enemy can give. let’s say 2.

Increasing the blue section max drops will result in chances of having 2 of the same things being dropped. how can I prevent that?

That one requires some more complex code… you’d need to copy the potential drops into a temporary collection, and then whenever an item is selected, remove that item from the list of potential drops…
That being said, this comes at some greater complexity, as the drop library is shared amongst all the enemies that use the same drop library…

This means that we’ll have to pass around the list of potential drops through the functions to make it work.
I’ll see what I can come up with, as this is a step or two more advanced than what we’ve already go going on.

1 Like

Thank you. alright, I see. so at this time the code I am using from the course inventory course is not designed to handle that kind of situation. needs a more complicated code.
I’m still at the ending part of the dialogue and quest system. and will continue to the shops and abilities course.

Here’s what I came up with. What we’re doing is creating a copy of the potential drops in the form of a list, so we can take advantage of List.Remove()… The copy is created when we call for the random drops, and passed around the method chains. Once a drop has been returned, if it is non-stackable, it is removed from the list. At the end of the GetRandomDrops() the list will automatically be garbage collected, preserving our original list for the next enemy to use the same DropConfig.

Revised DropLibrary.cs

using System.Collections.Generic;
using GameDevTV.Inventories;
using System.Linq;
using UnityEngine;

namespace RPG.Inventories
{
    [CreateAssetMenu(menuName = ("RPG/Inventory/Drop Library"))]
    public class DropLibrary : ScriptableObject
    {
        [SerializeField]
        DropConfig[] potentialDrops;
        [SerializeField] float[] dropChancePercentage;
        [SerializeField] int[] minDrops;
        [SerializeField] int[] maxDrops;

        [System.Serializable]
        class DropConfig
        {
            public InventoryItem item;
            public float[] relativeChance;
            public int[] minNumber;
            public int[] maxNumber;
            public int GetRandomNumber(int level)
            {
                if (!item.IsStackable())
                {
                    return 1;
                }
                int min = GetByLevel(minNumber, level);
                int max = GetByLevel(maxNumber, level);
                return UnityEngine.Random.Range(min, max + 1);
            }
        }

        public struct Dropped
        {
            public InventoryItem item;
            public int number;
        }

        public IEnumerable<Dropped> GetRandomDrops(int level)
        {
            if (!ShouldRandomDrop(level))
            {
                yield break;
            }

            List<DropConfig> potentialDropInstance = potentialDrops.ToList();
            for (int i = 0; i < GetRandomNumberOfDrops(level); i++)
            {
                yield return GetRandomDrop(level, potentialDropInstance);
            }
        }

        bool ShouldRandomDrop(int level)
        {
            return Random.Range(0, 100) < GetByLevel(dropChancePercentage, level);
        }

        int GetRandomNumberOfDrops(int level)
        {
            int min = GetByLevel(minDrops, level);
            int max = GetByLevel(maxDrops, level);
            return Random.Range(min, max);
        }

        Dropped GetRandomDrop(int level, List<DropConfig> potentialDropInstance)
        {
            var drop = SelectRandomItem(level, potentialDropInstance);
            if(!drop.item.IsStackable())
            {
                potentialDropInstance.Remove(drop);
            }
            var result = new Dropped();
            result.item = drop.item;
            result.number = drop.GetRandomNumber(level);
            return result;
        }

        DropConfig SelectRandomItem(int level, List<DropConfig> potentialDropInstance)
        {
            float totalChance = GetTotalChance(level, potentialDropInstance);
            float randomRoll = Random.Range(0, totalChance);
            float chanceTotal = 0;
            foreach (var drop in potentialDropInstance)
            {
                chanceTotal += GetByLevel(drop.relativeChance, level);
                if (chanceTotal > randomRoll)
                {
                    return drop;
                }
            }
            return null;
        }

        float GetTotalChance(int level, List<DropConfig> potentialDropInstance)
        {
            float total = 0;
            foreach (var drop in potentialDropInstance)
            {
                total += GetByLevel(drop.relativeChance, level);
            }
            return total;
        }

        static T GetByLevel<T>(T[] values, int level)
        {
            if (values.Length == 0)
            {
                return default;
            }
            if (level > values.Length)
            {
                return values[values.Length - 1];
            }
            if (level <= 0)
            {
                return default;
            }
            return values[level - 1];
        }
    }
}

2 Likes

This works great. Thank you very much. I tested it against my enemies and it didn’t drop same type of drops. :raised_hands:

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms