Buff/Debuff system

Hey all, so im working on a buff/debuff system for my turn-based RPG. I initially was thinking of setting it up as a scriptable object but realized it might cause some issues.

public class Buff : ScriptableObject
{
[SerializeField] public Stat affectedStat;
[SerializeField] public bool isDebuff = false;

[SerializeField] public float changeAmount = 0f;

[SerializeField] public int currentLifetime = 0;
[SerializeField] public int duration = 3;
}[/code]

I also want these to have behaviors, simple stuff like:

public void SetLifeTime()
    {
        currentLifetime = duration;
    }

   
public void OnEndOfTurn()
    {
        currentLifetime--;
       
        if(currentLifetime == 0)
        {
            // Destroy or Remove the buff
            // Return to original stat amount
        }
    }

public void ApplyStatChange()
{
//depending on if is debuff
    affectedStat += changeAmount || affectedStat -= changeAmount;
}

Ive looked over Buff System with Scriptable Objects for Unity - Unity3D Tutorial btw, doesnt make too much sense to me how he delcares a class as an abstract variable.

I was wondering if there was any way to :

  1. attach the current functions mentioned above to the scriptable object so i can manipulate them.

  2. create individual instances of these buffs so when i do manipulate the lifetime on one character, it doesnt change it for all characters with the same buff. (that being said i dont really like the idea of instantiating gameobjects as a child to the character, instead of just having a list/dictionary/array of “buffs” on the character himself)

Open to all advice, ideas, thoughts, etc. Thanks for your time and help!

The linked tutorial seems like a really good implementation, I’d consider working off of that to save yourself some headache of reinventing the wheel. You can obviously customize it as much as you need.

As for your questions:
1:
There’s nothing wrong with using an abstract class or an interface as a variable as long as the instance is concrete:

// both totally fine:
AbstractClass a = new ConcreteClass();
a.AbstractMethod();

IInterface i = new ClassThatImplementsIInterface();
i.InterfaceMethod();

It’s actually a good paradigm to use.

2:
You can add any methods you’d like to a ScriptableObject, they’re just classes at the end of the day.

3:
The tutorial does this by returning regular plain-old classes, return new TimedSpeedBuff(Duration, this, obj);, you’ll need to do something similar or copy your ScriptableObject with Instantiate() when you assign it as a buff.

yes i actually setup the scriptable object similar to the mentioned link/tutorial, just have never used that technique, i’ll have to play around. i just didn’t like the idea of the buff being a game object in the scene as i was thinking about just having the scrip obj get thrown into the character. thanks for posting i’ll play around with it a bit