Separate Item Actions for Same Category

I'm starting to set up some custom Item Actions for different items in my game (which is super easy by the way!), and I've run into a problem I should probably solve before creating any more actions.

Let's say that I want to have several items that are in the "Consumable" Item Category in the inventory database, but each of them performs a different function when I click "Consume" from the inventory menu (e.g., Health potion regenerates health, magic potion fills up magic bar, onion calls an animation to put them in a pot on the stove, or any other random function I'd want to call).

It appears that the CategoryActionItemSet will allow you to have have multiple actions for a specific category, but I don't want a menu of 25 things every time I click on an item in the inventory with 24 of them disabled. I'd just want the action that would specifically apply to the item selected to show up. I figure I could do this by creating individual categories for each item that has a function I want to call, but I'm sure there is a better way to do it and that would make the database quite messy.

Thoughts?

Thanks for all your help - totally appreciate how responsive you are as a developer.
 
That's a good point, I've had the same issue. I was thinking about solving this with a complex system but after some thinking I think I figured out a solution that could work out of the gate without any changes to the current system.

The idea is to use scriptable objects as attribute values to give functionality to your item. You could assign CategoryItemActions or custom scriptable object.

One way that could work for your particular case is to use an abstract ConsumableFunctionScriptableObject and set it as an item definition attribute. Then you can create as many derived classes as you have functions. In your Consume Item Action you would get the attribute value of the ConsumeFunction and invoke the function on it.

Let me know if that does not makes sense or If you have an idea on how to improve that kind of workflow. It's not something I've tried a lot but other users in the community liked the idea.
 
I believe I got it working! I'll share in case anyone else is trying to do this. There is one part at the beginning, which I feel is a bit of a workaround that you may have a better solution for.

Here's what I have:

1. This is the part that seemed like a little bit of a workaround. I tried to just add my abstract scriptable object class as a Type in Unit Options, but I couldn't get it to show up, but the below code worked.
Code:
using UnityEngine;

[System.Serializable]
public class ConsumableFunctionSO
{
    public ConsumeAction consumeAction; //ConsumeAction is the scriptable object abstract class
}

2. This is the scriptable object abstract class and scriptable object class that inherits it:
Code:
using UnityEngine;

public abstract class ConsumeAction : ScriptableObject
{
    public string name;
    public string description;
 
    public abstract void OnActivated();
}

Code:
[CreateAssetMenu(menuName = "Scriptable Objects/Consume Actions/Consume Lumen", fileName = "Consume Lumen")]
public class ConsumeLumen : ConsumeAction
{
    public override void OnActivated()
    {
        Debug.Log("Amazing! It works!"); //This is where you'd put the code you want to run for the item-specific consume action.
    }
}

3. Add the ConsumableActionSO Type to Tools > Opsive > Unit Options > Types:
Screen Shot 2020-09-21 at 8.20.47 PM.png

4. Add ConsumableActionSO to the Consumable Item Category in the Inventory System Manager:
Screen Shot 2020-09-21 at 8.20.23 PM.png

5. Create your scriptable object and add it to the Consume Action on your item of choice in the Inventory System Manager.

6. Create a new custom Item Action script and add the following code to the InvokeActionInternal() method:
Code:
consumeAction = item.GetAttribute<Attribute<ConsumableFunctionSO>>("Consume Action").GetValue();
consumeAction.consumeAction.OnActivated();

Make sure to declare your variable at the top of the class.
Code:
ConsumableFunctionSO consumeAction;

Note: I did something similar with the CanInvokeInternal() method as well.

7. Set up your Inventory Menu Category Item Action Set to use your new custom Item Action Script:
Screen Shot 2020-09-21 at 8.24.52 PM.png

8. Victory!

If you can see a way to omit the workaround in step 1 or if you have any ideas for improving or extending this, please let me know!

One question I did have... if I wanted to change the text that appears in the inventory panel popup (e.g., Use, Assign, Drop, etc.) so that it was unique for any given item (even though they are in the same ConsumableItemAction set), how would I go about that?
 
Last edited:
That's great!

For the first step I'm not sure why it wouldn't work. It might be a bug with UnitOptions. I'll look into it in more detail, but for now your workaround is good.

As for changing the name of the action, that's definitely possible, I do it when I write "equip" or "unequip" depending of whether the item is equipped or not.

In the "CanInvokeInternal" function you can set the "m_Name" field of the ItemAction to the name of the scriptable object.

Also I would pass your itemInfo and itemUser as parameters to your "OnActivated" function. This way you can have a reference to the player, inventory, item amount, etc...
 
Top