# Consumable Stats

## Example Script

The script below demonstrates how to add an event that triggers whenever any item is used (consumed). It’s recommended to treat this as a reference and implement your own version if you need similar functionality.

```csharp
using Esper.Inventool;
using Esper.Inventool.Items;
using Esper.Inventool.Stats;
using System.Collections;
using UnityEngine;

public class ConsumableEventExample : MonoBehaviour
{
    /// <summary>
    /// The player's stats.
    /// </summary>
    private CharacterStats characterStats;

    private void Awake()
    {
        // In this example, this component was added to the player object,
        // so we can get the character's stats with GetComponent
        characterStats = GetComponent<CharacterStats>();

        // Register the event on Awake
        Inventool.Inventory.onItemUsed.AddListener(OnConsumableUsed);
    }

    private void OnDestroy()
    {
        // Unregister the event when this object is destroyed
        Inventool.Inventory.onItemUsed.RemoveListener(OnConsumableUsed);
    }

    /// <summary>
    /// Handles consumable used.
    /// </summary>
    /// <param name="itemStack">The item stack used.</param>
    public void OnConsumableUsed(ItemStack itemStack)
    {
        // Safety null checks
        if (itemStack == null || !itemStack.item)
            return;

        // Ensure this is the correct item type
        if (itemStack.item.itemType.displayName != "Consumable")
            return;

        // Get the item dataset
        var dataset = itemStack.item.dataset as MyItemDataset;

        // Loop through each item stat
        foreach (var itemStat in itemStack.profile.stats)
        {
            // Check if the player has that specific stat
            var characterStat = characterStats.GetStat(itemStat.Identity);

            if (characterStat != null)
            {
                // If so, apply the consumable
                switch (dataset.consumableType)
                {
                    case MyItemDataset.ConsumableType.Restoration:
                        if (!dataset.isOverTime)
                        {
                            // Restore immediately
                            characterStat += itemStat;
                        }
                        else
                        {
                            // Restore over time
                            StartCoroutine(RestorationHelper(characterStat, itemStat, dataset.consumableLength));
                        }
                        break;

                    case MyItemDataset.ConsumableType.Buff:
                        // Apply the buff (with auto removal)
                        StartCoroutine(BuffHelper(characterStat, itemStat, dataset.consumableLength));
                        break;
                }
            }
        }
    }

    /// <summary>
    /// A coroutine that assists with over-time stat restoration (each tick delayed by a second).
    /// </summary>
    /// <param name="characterStat">The charater stat to restore.</param>
    /// <param name="itemStat">The stat to use as the restoration source.</param>
    /// <param name="length">The duration of the consumable's effect.</param>
    /// <returns>An enumerator that performs over-time stat restoration when used as a coroutine.</returns>
    private IEnumerator RestorationHelper(Stat characterStat, Stat itemStat, float length)
    {
        // Calculate ticks based on length (1s = 1 tick, 1.5s = 2 ticks)
        var ticks = Mathf.CeilToInt(length);

        // Calculate value added per tick
        var overTimeValue = itemStat.value / ticks;

        // Tick loop
        for (int i = 0; i < ticks; i++)
        {
            // Restore the stat
            characterStat += overTimeValue;

            // Yield for a second before the next tick
            yield return new WaitForSeconds(1f);
        }
    }

    /// <summary>
    /// A coroutine that assists with buffs. The buffs are removed automatically.
    /// </summary>
    /// <param name="characterStat">The charater stat to apply the buff to.</param>
    /// <param name="itemStat">The stat to use as a buff.</param>
    /// <param name="length">The duration of buff.</param>
    /// <returns>An enumerator that performs over-time stat restoration when used as a coroutine.</returns>
    private IEnumerator BuffHelper(Stat characterStat, Stat itemStat, float length)
    {
        // Apply the buff
        characterStat.Combine(itemStat);

        // Yields for the duration length
        yield return new WaitForSeconds(length);

        // Remove the buff
        characterStat.Uncombine(itemStat);
    }
}
```

### Important Notes

* It’s recommended to enable **Update Current Value With High Value** in the Stat Identity settings if you want buffs to affect the current value as well (by default, only the high value is modified).
* The [dataset](#dataset-used) below must be set up.
* This script is a **component** and must be attached to the same GameObject that holds the player's **CharacterStats** component.
* Supports both **instant** and **over-time** stat restoration consumables.
* Uses **coroutines** for over-time effects — if a coroutine is interrupted (e.g., the GameObject is disabled), over-time affects may be canceled and buffs may not be properly removed. You’ll need to implement your own stat-tracking logic to handle such cases.
* **No UI functionality** is included in this script.

### Dataset Used

This is the custom item dataset used for the example above. Click [here](https://stylishesper.gitbook.io/inventool/scripting/api/items/dataset) to learn more about datasets.

```csharp
using Esper.Inventool.Items;
using UnityEngine;

[CreateAssetMenu(fileName = "My Item Dataset", menuName = "Inventool/Datasets/My Item Dataset")]
public class MyItemDataset : Dataset
{
    /// <summary>
    /// The type of consumable.
    /// </summary>
    public ConsumableType consumableType;

    /// <summary>
    /// The duration of the consumable's effect (e.g., buff duration or restoration period).
    /// Ignored for consumables that apply their effect instantly.
    /// </summary>
    [Min(0)]
    public float consumableLength;

    /// <summary>
    /// Determines whether the consumable's effect is applied gradually over time instead of instantly.
    /// Ignored for buffs.
    /// </summary>
    public bool isOverTime;

    /// <summary>
    /// Specifies how a consumable item affects the player's stats.
    /// </summary>
    public enum ConsumableType
    {
        /// <summary>
        /// Uses the item's stats to restore or replenish a specific stat (e.g., health or mana).
        /// </summary>
        Restoration,

        /// <summary>
        /// Applies the item's stats as a temporary buff that enhances attributes for a limited duration.
        /// </summary>
        Buff
    }
}
```
