You are on the right track. That is where I would start. All of your components share the identifier and quantity. It makes sense to add chance property and use composite pattern.
public class Droppable
{
public string Name { get; private set; }
public uint QTY { get; private set; }
public float Chance { get; private set; }
public Droppable(string name, float chance, uint qty)
{
this.Name = name;
this.QTY = qty;
this.Chance = chance;
}
public virtual bool ShouldDrop()
{
// random drop check
}
}
You can then create your loot table extending Droppable
component.
public class DropBundle extends Droppable
{
public bool CollectAll { get; private set; }
private List<Droppable> _items;
public DropBundle(string name, float chance, uint qty, bool collectAll, List<Droppable> items): base(name, chance, qty)
{
CollectAll = collectAll
_items = items;
}
public override bool ShouldDrop()
{
// random drop check and if yeas run should drop check for other items
}
}
You also need your item class that would also extend Droppable
public class DropItem extends Droppable
{
public override bool ShouldDrop()
{
// random drop check
}
}
Notice CompositeItemDropBundle
holds references to other Droppable
components. That means you can then next them as much as you want, eg.:
- 5% of finding 10 gold coin (DropItem)
- 10% of finding a coin (CompositeItemDropBundle) wich can be either gold (20%) or silver (80%)
- 20% of finding a chest (CompositeItemDropBundle) that can have 10% chance of finding a coin (CompositeItemDropBundle) which can be either gold, silver or copper, etc.
All of those scenerios are then possible without changing dependency tree too much. The only thing you have to remember is obviously implement randomisation and keep in mind that sum of chances of nested droppables should be 1 (100%) for simplicity sake.
Another great advantage of using composite pattern is ability to later on use that implementation for data you can dynamically read from static XML (or JSON) file.