enemyStatus/BurningEnemyStatus.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sandbox;

public class BurningEnemyStatus : EnemyStatus
{
	private TimeSince _sinceDamageTime;
	private const float DAMAGE_INTERVAL = 0.42f;

	public float Lifetime { get; set; }
	public float SpreadChance { get; set; }

	public Player Player { get; set; }

	public float Damage { get; set; }

	private TimeSince _damageOtherTime;

	public static float BURN_REAPPLY_COOLDOWN = 0.5f;

	public int NumStacks { get; set; }

	public BurningEnemyStatus()
	{

	}

	public override void Init( Enemy enemy )
	{
		base.Init( enemy );

		Enemy.CreateBurningVfx();
	}

	public void AddStack( float damage, float lifetime, float spreadChance )
	{
		var maxStacks = (int)Player.Stats[PlayerStat.MaxFireStacks];

		if ( NumStacks >= maxStacks )
		{
			//Refresh();
		}
		else
		{
			Manager.Instance.PlaySfxNearby( "burn", Enemy.Position2D, pitch: Utils.Map(NumStacks, 0, 7, 1.35f, 1.65f), volume: 0.5f, maxDist: 3f );
			NumStacks = Math.Min( NumStacks + 1, maxStacks );

			if ( Enemy.BurningVfx.IsValid() )
				Enemy.BurningVfx.SetStacks( NumStacks );
		}

		Damage = damage;
		Lifetime = lifetime;
		SpreadChance = spreadChance;

		//Log.Info( $"NumStacks: {NumStacks} maxStacks: {maxStacks}" );
	}

	public override void Update( float dt )
	{
		if ( Enemy == null || !Enemy.IsValid() )
			return;

		//Gizmo.Draw.Color = Color.White;
		//Gizmo.Draw.Text( $"{NumStacks}\n{ElapsedTime}", new global::Transform( (Vector3)Enemy.Position2D + new Vector3( 0f, -0.5f, 0f ) ) );

		if ( ElapsedTime > Lifetime )
		{
			if(NumStacks > 0)
			{
				NumStacks--;

				if ( Enemy.BurningVfx.IsValid() )
					Enemy.BurningVfx.SetStacks( NumStacks );

				ElapsedTime = 0f;
			}
			else
			{
				Enemy.RemoveEnemyStatus( this );
				return;
			}
		}

		if ( _sinceDamageTime > DAMAGE_INTERVAL )
		{
			Enemy.DamageFire( Damage * (NumStacks + 1), Player );
			_sinceDamageTime = 0f;
		}
	}

	public override void Remove()
	{
		Enemy.RemoveBurningVfx();
	}

	public override void Refresh()
	{
		ElapsedTime = 0f;
	}

	public override void Colliding( Thing other, float percent, float dt )
	{
		bool didDamage = false;

		if ( other is Enemy enemy && !enemy.IsDying && !enemy.HasEnemyStatus( this ) )
		{
			if ( _damageOtherTime > DAMAGE_INTERVAL )
			{
				// should stack damage apply to nearby enemies?
				enemy.DamageFire( Damage, Player );

				if ( Game.Random.Float( 0f, 1f ) < SpreadChance )
				{
					var burning = enemy.GetEnemyStatus<BurningEnemyStatus>();
					if ( burning != null )
					{
						burning.AddStack( Damage, Lifetime, SpreadChance );
					}
					else
					{
						enemy.Burn( Player, Damage, Lifetime, SpreadChance );
						Manager.Instance.PlaySfxNearby( "burn", enemy.Position2D, pitch: Sandbox.Game.Random.Float( 1.15f, 1.35f ), volume: 0.7f, maxDist: 4f );
					}

					enemy.TimeSinceBurn = 0f;
				}

				didDamage = true;
			}
		}
		else if ( other is Player player && !player.IsDead )
		{
			if ( _damageOtherTime > DAMAGE_INTERVAL )
			{
				// should stack damage apply to nearby player?
				player.Damage( Damage );
				Manager.Instance.PlaySfxNearby( "burn", player.Position2D, pitch: Game.Random.Float( 1.15f, 1.35f ), volume: 0.6f, maxDist: 4f );
				didDamage = true;
			}
		}

		if ( didDamage )
			_damageOtherTime = 0f;
	}
}