Overview

The inventory system has two distinct layers that work together during a level run.

LayerClassLifetimeWhen to use
PersistentPlayerInventory.currentEntire game sessionReading stats, checking equipped gear, after level completion
Executioncontext.inventoryOne level runConsuming items, adding pickups, checking inventory inside Tick()

Always use context.inventory inside a Tick() override. The execution inventory is a deep copy of PlayerInventory.current that gets committed back only when the level is completed successfully — so failed runs do not consume items permanently.


1 — Reading Inventory in an Instruction

Access the execution inventory through the ExecutionContext passed to Tick(). The most common operations are checking whether an item is present and consuming it.

public override IEnumerator Tick(ExecutionContext context)
{
    // Check before consuming — give feedback if the item is missing
    if (!context.inventory.ContainsItem(requiredItem))
    {
        NotificationCenter.Notify(NotificationCenter.MessageType.Warning, "No item available");
        yield break;
    }

    // Consume one unit; TryUseItem returns false if the item is not present
    if (context.inventory.TryUseItem(requiredItem))
    {
        // Apply the item's effects, play animation, etc.
        context.player.UseItem(requiredItem);
    }

    yield return null;
}
💡
Use TryUseItem, not TryRemoveItem TryUseItem decrements the stack count and removes the slot only when it reaches zero. TryRemoveItem removes the entire slot regardless of stack size. For consumables, always use TryUseItem.

2 — Adding Items from an Interactable

When a player collects a pickup or opens a chest, call TryAddItem on the execution inventory inside the Interact() method. The context property is available on any class that extends ExecutionContextElement.

public class InteractableObject_Sign : ExecutionContextElement, IInteractable
{
    [SerializeField] Item item;
    [SerializeField] int amount = 1;
    [field: SerializeField] public UnityEvent OnInteract { get; set; }

    public bool automatic => false;
    public bool Validate() => item != null;

    public void Interact()
    {
        if (context.inventory.TryAddItem(item, amount))
        {
            OnInteract?.Invoke();
            Destroy(gameObject);
        }
        else
        {
            NotificationCenter.Notify(NotificationCenter.MessageType.Warning, "Inventory full");
        }
    }
}

3 — Checking Carry State

The carryTarget and carryingObject members of ExecutionContext track what the player is currently holding. Check carryingObject before actions that require the player's hands to be free.

public override IEnumerator Tick(ExecutionContext context)
{
    if (context.carryingObject)
    {
        NotificationCenter.Notify(NotificationCenter.MessageType.Warning,
            "Can't do this while carrying something");
        yield break;
    }

    // ... rest of instruction logic
    yield return null;
}

4 — Creating Item Assets

Items are ScriptableObject assets. Create them from the Unity menu and assign them to interactable prefabs or instructions.

  1. Right-click in the Project window → Create → Loop Adventure → Inventory → Item.
  2. Set Display Name and Description — these appear in the inventory UI.
  3. Assign a Sprite for the item icon.
  4. Enable Stackable if multiple copies should share one inventory slot.
  5. Add Effects if using the item should modify stats. Each effect targets a Stat asset with a numeric value and an optional duration in turns.
  6. Save the asset under Assets/Scriptable Objects/Items/.

5 — Creating Equipment Assets

Equipment extends Item with a slot type and stat bonuses. Equipped gear provides passive stat bonuses without being consumed.

  1. Right-click in the Project window → Create → Loop Adventure → Inventory → Equipment.
  2. Fill in all Item fields (Display Name, Sprite, etc.).
  3. Set Type — this determines which equipment slot it occupies (Weapon, Shield, Helmet, Armor, or Boots).
  4. Enable Two Handed if the weapon should also occupy the Shield slot.
  5. Add Stats entries — pair a Stat asset with a bonus value. Positive values increase the stat, negative values reduce it.
  6. Save the asset under Assets/Scriptable Objects/Equipment/.
💡
Stat values at runtime Equipped stats are summed across all slots by PlayerInventory.current.GetStatValue(stat). The built-in player controller calls this for damage and defense automatically. Add your own Stat assets to extend the system.

6 — Creating Stat and Effect Assets

Stat

A Stat is a named data key — it does not store a value itself. Stats link equipment bonuses, item effects, and character receivers together.

  1. Right-click → Create → Loop Adventure → Inventory → Stat.
  2. Set Display Name and an Icon — shown in the UI when this stat is affected.
  3. Save under Assets/Scriptable Objects/Stats/ and reference it in Equipment.Stats or Effect.Target Stat.

Effect

Effects are embedded in Item assets (not separate assets). Add them in the Item inspector under the Effects list.

FieldDescription
Target StatThe Stat asset this effect modifies.
ValueAmount added to the stat. Negative values reduce it.
DurationTurns the effect lasts. 0 means instant and permanent (for this run).
Apply Per TurnIf enabled, applies the value once per turn instead of once upfront — use for regeneration or damage-over-time. Ignored when Duration is 0.