Diablo/Path of Exile like Item system

Hey everyone!

Basically i want to create an item/equipment system that works similar to the systems in Diablo or Path of Exile.
The main idea would be to have equipment types (Weapon, Armor) and these types are separated in base types. For example, an iron helmet could have 5 different base types. These base types differ in the level requirement and the base (armor) value.
Simple Helmet: Lvl 5, Armor: 10
Normal Helmet: Lvl 10, Armor: 20

Every equipment item can also appear in a different rarity. The rarity types can be common, uncommon, rare and legendary. The rarity decides which properties are added to the item. The higher the rarity the more properties an item can get. Path of Exile uses an affix/prefix system, which means a rare item can get 3 affixes and 3 prefixes.

Now my question is: What is the best way to implement such a system?
Would xml be a good way to create a database for the base types? And how are the properties added? I would want to create a random item. That means it would have to choose a random base type, a random rarity and then add random properties to the item depending on the base type. The properties (affixes, prefixes) can also have a random value in a certain range.
I would be very glad if anyone could guide me in a good direction.

There are literally a Billion ways of doing this, all of them correct.

I did something similar using classes and inheritance, but later found out that you can do everything with a simple dictionary, since Special Abilities etc have to be coded for.

One Thing to note here is that ‘rarity’ is not really a property of the item itself, but something that is relevant only during creation of the item. So I ended up creating small ‘effect’ objects that describe damage and protection effects, and added them to the dictionary that describes the item. Rare items got more effects than others, and during combat I ‘proc’ all effects at the appropriate time (you’ll find that you’ll have to do multiple passes if your items have effects outside their main function, e.g. if your armor adds inteligence, you’ll have to gather that during the character’s gather attributes cycle etc).

Anything will work, but you should take the time to sketch it out on paper before you put your fingers to the Keyboard, as screwing up here will mean a lot more work later on.

So you are not using a class/inheritance structure anymore but rather a dictionary for every item that contains only the valid properties of that item?
Good point with the rarity!

Luckily i am just at the start of item creation, that’s why i am asking. I just want to make sure that i choose the best option for my system. I have looked into ScriptableObjects and xml and out of these two the xml solution seems more fitting. How did you create ‘random’ items in your project?

I limited the class/inheritance stuff to the ‘effect’ objects that are attached to the item. That way you are much more flexible.

Random object creation is always going to be a mess, because you almost never want truly random objects, but a specific item (e.g. a weapon) with some set properties, and some random enhancements. For this I created a pool of stock items that I knew worked, and then simply added enhancement properties (effects) on a random-ish way that ensured that the item remains usable (this is especially imortant if you also allow for detrimental effects as I did, where some of the advantages have to be paid by disadvantages). I built three main EnhanceItem procs, one each for weapons, gear (armor), and ‘Other’ (trinkets munition, etc) that all take an Input item to modify. The app never creates a truly random item.

Could you please expose more details? I’m trying to build a JRPG, and I’m still figuring out how to manage stats and items through dictionaries and/or hashtables.

Currently for my stats I have something like this: (this example might be useful for OP).

protected Hashtable baseStats = new Hashtable();

baseStats.Add("attack", 4);
baseStats.Add("defense", 3);
baseStats.Add("speed", 1.2f); // Yes, I need to mix ints and floats in this case
// etc.

But, I’m having doubts if this is a good coding practice. Due to the fact that when I have to calculate literally anything I have to get the value from the hastable and properly cast it in order to be used in a formula.

As I said, almost everythng works, and your’s is as good a try as anyone’s, Performancewise you’ll soon notice that the stats only Change at key points (when equipping items, levelling) so most values can be easily cached.

During combat, you’ll iterate the various items’ special abilities (not the base stats) multiple times (prep, attack, defend, postproc) and yes, that takes a little bit of time, but accessing hash tables is neglegible compared to the time the graphics effects take up, so don’t worry too much about that.

Thanks for the replies and the example you provided!
Generally, i like the idea if saving the items in a dictionary. However i’m still not quite sure which items i would store there. My approach right now would be to store the base item types in one or more xml files, read the data from the file and then add the properties ‘randomly’. The generated item could then be stored in a dictionary, lets say for example in the inventory.
Is having a mixture between different methods (e.g. class/inheritance and xml) a bad idea and should be avoided?

Actually, I like using a mixture of both, because they work well together - combine the power of inheritance with the flexibility of dictionaries. Throw in the occasional Interface for good measure, just make sure the underlying principles remain clear (don’t run roughshod on your foundation: while it may be cool to create a piece of armor that can also double as a weapon, it’ll break your game code’s serviceability in the long run). The trick is to find out which to use when to coax out the optimum.

If you know your way around with ECS then realising this is somewhat easier.
Cause then you can just decorate entities with whatever you want.
So if you want the system to randomly create a helmet gear piece with epic rarity and have it enhance your luck stat by a 100. you just decorate the entity and attach a Helmet tag with Epic rarity tag and the luck stat to that entity.

That’s what I’ve learned from ECS that inventory systems / equipment systems are a lot easier to setup with ECS.
But ECS is not all that simple, the data layout is simple but I still have troubles connecting them together. It has it’s own learning curve as it is Data Oriented Design instead of Object Oriented Programming.

As for a monobehaviour OOP way, I’d refrain from using XML as it is super slow. If you’re going to serialize things it is easier to use Json (debug) / Bson (release) for serialization of items.
As for the setup of an item system yeah, there are a billion ways of setting that up as @csofranz mentioned.
It depends on whether it will be a performance critical factor. I spent a lot of time creating an inventory system in different ways. But you could experiment with an ECS kind of like system but then in OOP monobehaviours. i.e. create stat components or effect components and decorate them onto your prefab. Once the prefab is instantiated you fill a list / dict / hashtable or whatever suits your needs and use that as reference for what the item actually is. But ofcourse it won’t be as performant as ECS. On the other hand if you ever convert from monobehaviours to ECS then this’ll be easier because data is already split into components.

bottomline, experiment experiment and experiment. See what you’re comfortable with and try things out. For every problem there are a lot of solutions. Item systems can be as complex as you want but you have to work with it. (or your designer does in some cases).

I’ve probably tried to setup an item & inventory system like 4 or 5 times by now with different approaches. Because I just like to setup these systems. Do I use them? nope they’re just experiments. I’ll probably experiment once again when 2019.3 is out with a more easier ECS way of doing things. Now it is a lot of boilerplate code which soon gets worked away under a few attributes.