using System.Collections; using System.Collections.Generic; using UnityEngine; namespace MoreMountains.Tools { /// /// A loot table helper that can be used to randomly pick objects out of a weighted list /// This design pattern was described in more details by Daniel Cook in 2014 in his blog : /// https://lostgarden.home.blog/2014/12/08/loot-drop-tables/ /// /// This generic LootTable defines a list of objects to loot, each of them weighted. /// The weights don't have to add to a certain number, they're relative to each other. /// The ComputeWeights method determines, based on these weights, the chance percentage of each object to be picked /// The GetLoot method returns one object, picked randomly from the table /// /// /// public class MMLootTable where T:MMLoot { /// the list of objects that have a chance of being returned by the table [SerializeField] public List ObjectsToLoot; /// the total amount of weights, for debug purposes only [Header("Debug")] [MMReadOnly] public float WeightsTotal; protected float _maximumWeightSoFar = 0f; protected bool _weightsComputed = false; /// /// Determines, for each object in the table, its chance percentage, based on the specified weights /// public virtual void ComputeWeights() { if (ObjectsToLoot == null) { return; } if (ObjectsToLoot.Count == 0) { return; } _maximumWeightSoFar = 0f; foreach(T lootDropItem in ObjectsToLoot) { if(lootDropItem.Weight >= 0f) { lootDropItem.RangeFrom = _maximumWeightSoFar; _maximumWeightSoFar += lootDropItem.Weight; lootDropItem.RangeTo = _maximumWeightSoFar; } else { lootDropItem.Weight = 0f; } } WeightsTotal = _maximumWeightSoFar; foreach(T lootDropItem in ObjectsToLoot) { lootDropItem.ChancePercentage = ((lootDropItem.Weight) / WeightsTotal) * 100; } _weightsComputed = true; } /// /// Returns one object from the table, picked randomly /// /// public virtual T GetLoot() { if (ObjectsToLoot == null) { return null; } if (ObjectsToLoot.Count == 0) { return null; } if (!_weightsComputed) { ComputeWeights(); } float index = Random.Range(0, WeightsTotal); foreach (T lootDropItem in ObjectsToLoot) { if ((index > lootDropItem.RangeFrom) && (index < lootDropItem.RangeTo)) { return lootDropItem; } } return null; } } /// /// A MMLootTable implementation for GameObjects /// [System.Serializable] public class MMLootTableGameObject : MMLootTable { } /// /// A MMLootTable implementation for floats /// [System.Serializable] public class MMLootTableFloat : MMLootTable { } /// /// A MMLootTable implementation for strings /// [System.Serializable] public class MMLootTableString : MMLootTable { } }