Item Skills

Due to the incredible flexibility of the Attribute system it is often asked how could an Item be used as a Skill.
For our purposes a skill is an Item which has a functionality which can change between items within the same category. This is different from the classic Category Item Action Set system used in the UI where any Item within a category will run the same Item Action.

There are no right or wrong answers on how to implement Item Skills. It all dependents on what you wish to achieve and what are the existing systems in your game. Here are some the most common options but note they are not the only ones possible.

Option 1: Use a Scriptable Object as an Attribute

The first option is to use a Scriptable Object Attribute on the Item. This way anywhere in code you may get the attribute of your item and call the function on it, passing the Item and other information as parameter.

The type of Scriptable Object can be custom or you may simply use an “Item Action Set”.

Example

Lets set an Item Action Set attribute. It Could be set on any of the Attribute Collections, although most likely you will wish to add it as an Item Definition Attribute.

Through code you may then get that Scriptable Object and invoke the Item Action on it:

/// <summary>
/// Check if the action can be invoked.
/// </summary>
/// <param name="itemInfo">The item.</param>
/// <param name="itemUser">The item user (can be null).</param>
/// <returns>True if the action can be invoked.</returns>
protected bool TryUseItem(ItemInfo itemInfo, ItemUser itemUser){
	 
	 //Cannot use the item if null.
    if (itemInfo.Item == null) { return false; }

	 //Get the Attribute with your scriptable object 
    var attribute = itemInfo.Item.GetAttribute<Attribute<ItemActionSet>>(m_AttributeName);

	 //Make sure the attribute exists
    if (attribute == null) { return false;}

	 // Get the scriptable object (in this case the Item Action Set)
    var actionSet = attribute.GetValue();
    if (actionSet == null) { return false; }

    //Since the Item Action has a list of items we need to choose which one we will use by specifying the index (or we could have executed all the actions).
    if (m_ActionIndex < 0 || actionSet.ItemActionCollection.Count >= m_ActionIndex) { return false; }

    // Use the item action on a single item, or the entire amount of item?
 	 if (m_UseOne) { itemInfo = (1, itemInfo); }

    //Call the function on the scriptable Object.
    actionSet.ItemActionCollection[m_ActionIndex].InvokeAction(itemInfo,itemUser);

	 // You may wish to remove the item once used.
    if (m_RemoveOnUse) {
        itemInfo.ItemCollection?.RemoveItem(itemInfo);
	 }

	 return true;
}

In the case of Item Action Set as an attribute you may use the “Use Item Action Set Attribute” Item Action to use the items as skills within the UI with breeze. It essentially does the same as the code example above.

And from there you may now add a different Scriptable Object (with the same base type as the one set as attribute) to each item.

Tip: Make good use of the Item User parameter to get any Component on its game object. It is very useful to get the transform of the Character to spawn things for example.

Option 2: Add Components next to the Item Object

This option is only relevant if the item you plan to use as skills are spawned as Item Objects within the game world, in the scene.

The idea is to change functionality of the Item Object by editing some of the components on its game object depending on the Item bound to the Item Object.

There are multiple ways to do this. One option is to use Item Object Behaviours Handler with many Item Object Behaviours and change the index of the Behaviours in the array of Behaviours.

Option 3: Combine Option 1 & 2

The most versatile option is this one. Use a Scriptable Object on the Item to get different functionality for each Item.
If that functionality requires additional information/functionality if may get it components in the scene through the Item User. For example the Item Action may simply call a Restore Health function on the character.

Tip: Use the itemUser.gameobject.GetCachedComponent<MyComponentType>() function to be more efficient when getting the same component multiple times.