RPG buffs and debuffs

I’ve always had an issue with this and still haven’t found the best way to handle it. How do you apply buffs and debuffs quickly and easily? They should be able to applied to either the player or any enemies.

Example:

Debuff
Type: poison
Description: Does 10 damage every second for 5 seconds.

Now for the confusing part. Being able to apply multiples of the same debuff on a single target, removing specific debuffs ( poison, ice, ect. ), and adjusting damage taken from these debuffs compared to resistances such as poison resistance.

How you do this really depends on all of the other systems that you’re employing.

I use a StatusEffect class and each character and enemy has a StatusEffects collection. When they’re affected by a buff or debuff, and instance of that effect is added to their list. The turn manager then processes each entry in their collection every turn and applies the effect. Additionally, each effect has a duration and an elapsed property. Elapsed is incremented every turn until it reaches duration, and then the effect is removed from their collection.

Anyway, that’s one way to do it. There are many other ways.

2 Likes

Well the one idea I have is creating a debuff class, then create a debuff array of each debuff. Then from there create a debuff list for each enemy. It’s just I am unsure how to adjust time for each debuff added to a list so it applies damage and has a timer for each. It kind of confuses me still.

Is your game turn-based?

I think, you need something like this:

/// All buffs and debuffs interface
public interface IBuffable
{
    void Apply(Component victim);
    bool Finished { get; }
}

/// Piosion buff
public class Poison : IBuffable
{
    public int Value;
    public bool Finished
    {
        get
        {
            /// LOGIC OF FINISHING Poison (for example, return True after 5 calls, or after 10 seconds, and so on)
            return false;
        }
    }

    public void Apply(Component victim)
    {
        if (victim as Player != null)
            ((Player)victim).Health -= Value;

        if (victim as Enemy != null)
            ((Enemy)victim).Health -= Value;
    }
}

public class Human : MonoBehaviour
{
    public int Health;
    public List<IBuffable> Buffables = new List<IBuffable>();

    public void AddBuffable(IBuffable buff)
    {
        Buffables.Add(buff);
    }

    public void Update()
    {
        for (int i = 0; i < Buffables.Count; i++)
        {
            Buffables[i].Apply(this);

            if (Buffables[i].Finished)
                Buffables.Remove(Buffables[i]);
        }
    }
}

public class Player : Human
{
    /// TODO:
}

public class Enemy : Human
{
    /// TODO:
}

Real time rpg

Still a little confused by this.Since I’ve only worked with very basic classes so far. Will this handle timers as well? I pretty much have my system all setup how I wanted it but just am unsure about setting up timers since I haven’t been able to get them to work inside of a class. Is there a simple way once I add an item to a list to grab a duration variable and just make each one have their own timers for counting down? Like using a for loop to check each buff in the List and if any of them get to 0 then remove them from the List. If I knew how to handle time I could get what I needed done.

Hi, jessee03,
I add some lines of code to support duration of buffs and comment them with CAPSLOCK :slight_smile:
I think it should works well with timers.

    /// All buffs and debuffs interface
    public interface IBuffable
    {
        void Apply(Component victim);

        /// ADD FINISHTIME PROPERTY TO ALL BUFFS AND DEBUFFS
        float FinishTime { get; set }
    }
     
    /// Piosion buff
    public class Poison : IBuffable
    {
        public int Value;
        public float FinishTime { get; set }
     
        public void Apply(Component victim)
        {
            if (victim as Player != null)
                ((Player)victim).Health -= Value;
     
            if (victim as Enemy != null)
                ((Enemy)victim).Health -= Value;
        }
    }
     
    public class Human : MonoBehaviour
    {
        public int Health;
        public List<IBuffable> Buffables = new List<IBuffable>();
     
        public void AddBuffable(IBuffable buff)
        {
            /// SETUP TIME WHEN BUFF WILL FINISH (CURRENT TIME + 30 SECONDS)
            buff.FinishTime = Time.time + 30;
            Buffables.Add(buff);
        }
     
        public void Update()
        {
            for (int i = 0; i < Buffables.Count; i++)
            {
                Buffables[i].Apply(this);
     
                /// CHECK IF CURRENT TIME IS GREATER THEN FINISHTIME OF BUFF
                if(Time.time >= Buffables[i].FinishTime)
                    Buffables.Remove(Buffables[i]); /// REMOVE
            }
        }
    }
     
    public class Player : Human
    {
        /// TODO:
    }
     
    public class Enemy : Human
    {
        /// TODO:
    }

Even if Patico’s code works as intended, though in my opinion your “spell” effect (or whatever you call it) should be a MonoBehaviour itself to be instantiated on the human target else you will need to create a class for every “spell” even if it’s only the duration and damage to change.

Probably the easiest way I suggest is to have a base timed effect class, so you basically will create the classes for your effects inheriting from it.

For example the base class would be something like this:

using UnityEngine;
using System.Collections;

public class TimedEffect : MonoBehaviour {
	
	public float duration; // when it should expire?
	public float startTime; // should delay the (first) effect tick?
	public float repeatTime; // how much time between each effect tick?
	[HideInInspector]
	public Human target;
	
	void Start () {
		// Apply the effect repeated over time or direct?
		if (repeatTime > 0)
			InvokeRepeating("ApplyEffect", startTime, repeatTime);
		else
			Invoke("ApplyEffect", startTime);
		// End the effect accordingly to the duration
		Invoke("EndEffect", duration);
	}
	
	protected virtual void ApplyEffect () {
	}
	
	protected virtual void EndEffect () {
		CancelInvoke();
		Destroy(gameObject);
	}
}

An example of damage over time:

using UnityEngine;
using System.Collections;

public class DamageOverTime : TimedEffect {
	
	public int damage;
	
	protected override void ApplyEffect () {
		target.TakeDamage(damage);
	}
}

An example of stat (strength, constitution, speed, etc) buff/debuff (for debuff you just set buffValue to a negative value):

using UnityEngine;
using System.Collections;

public class StatBuff : TimedEffect {

	public BaseStat stat;
	public int buffValue;
	
	protected override void ApplyEffect ()
	{
		target.BuffStat(stat, buffValue);
	}
	
	protected override void EndEffect ()
	{
		target.BuffStat(stat, -buffValue);
		base.EndEffect ();
	}
}

To use this you will Instantiate the effect prefab and assign the “target” (since Start should be theoretically called in the next frame it should work, else you could turn the Start function in TimedEffect into another named public function and call it after Instantiate).

PS: notice that I didn’t change directly the health value of the target but it calls TakeDamage (that should be in the target script), because you need at least few things to do upon each damage taken (at least verify that the health doesn’t never be negative, and probably you will want to do something when it reaches 0).

1 Like

SkaredCreations, you solution is better :sunglasses:

HEY! I watch you on YouTube!

SkaredCreations that seems to be exactly what I was looking for :slight_smile: Very nicely done! Also thanks Patico but ya that’s a lot of extra code I think, bet it still works all the same though :o

There is a program on the asset store specifically for this! BuffMaster Status Effects