Programming "Drop Chance" and avoiding a circular logic/dependency issue?

Hi, I need some help with the logic of spawning items with predefined a chance.
I have a base item class.
I then have blueprints based on this class, which each define how they affect the player on pickup, their individual drop chances etc. All the blueprints are added to the pool of items that can spawn automatically by looking for all the blueprints in their respective folder.

Now, I wish to program them to have a chance to drop on a kill based on their inherent drop chance.
I’m thinking I need to have a chance for anything to drop in the first place (so that the chance to get something isn’t affected by the amount of items), then get the drop rate of all the items, pool the total together, and roll for which one drops. (if the first one has a drop chance of 10, any roll between 1-10 gives this item, the next has a drop chance of 5, so 11-16 gives this, etc)

So far so good, however, the issue comes with actually getting the drop chances of all the items for evaluation.
How would I get their drop chance value without spawning them first?

My current thought is to have a loot table that’s seperate from the items themselves, but then I would have to hard code every single drop into the loot table outside of making the items and I would like to keep the ability to just add items with more blueprints on the fly and just scan for them, including their chance to drop.

Is this doable?

1 Like

It might be possible, depending on how exactly you store the information about which Blueprints live in which folder (as a path string? UClass? Something else?). However, there is a better way to do what you want; better in the sense that it’s more “canonical” because it’s closer to how Epic handles it and it’ll probably scale better than your current solution. Which one do you want to know more about?

1 Like

Sure, let me know the alternative method that scales better.

Instead of a loot table for each item, why not make it for an item category (rarity maybe?) and apply said category to those items.

If the drop chance property is an EditDefaultsOnly property (of your base class) you can still set it on each Item class (Blueprints or native constructor) and get it without spawning an instance using the CDO of that class.

1 Like

That sounds like what I’m looking for.
I was unaware of CDO, but it looks like they are limited to Objects?

My items are actors (or maybe that’s not a relevant distinction anymore?)

So, what @UnrealEverything wrote is the way to go forward with your original plan. If you have a file path you can use StaticLoadClass to get a UClass and call UClass::GetDefaultObject to get the CDO and read every property from there. This option would probably be less work for you. AActor inherits from UObject, so there’s no problem there.

The other way is to use data assets and the asset manager. Here are some links to get you started:

It would go like this: You create a class that inherits from UPrimaryDataAsset. This is the base class for all item data assets and it does what it says: It contains data about your item, whatever you want. Spawn rates, damage types, level, price etc. One of the properties of this asset would then be the associated Blueprint class that gets spawned when the item needs to be represented as an object in the level, whether attached to the player (weapons and gear) or lying around on the floor (pickups).

You create new items by creating a new data asset in the editor and selecting your base class as the asset’s parent class. After that, you are free to change any properties you like. Data assets can be loaded whenever you need them, synchronously or asynchronously. That also means you have access to an item’s properties without ever having it to be spawned in the world. That helps with stuff like shops and inventory systems and the like.

4 Likes

Thanks! The asset manager looks very interesting, especially for more dynamic settings, but it’s probably a bit beyond of the scope of what I’m currently working on. But definitely something to look out for for future projects!

You can cast the CDO to your Item class as with any object. I believe there is a templated version that does the cast for you. If you’re using TSubclassOf<YourItemClass> its GetDefaultObject function also returns a YourItemClass* directly.