Code/Emissions/ConchplexBurstEmission.cs
using Sandbox;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using static Sandbox.PhysicsContact;

namespace ConchplexEmitters;

/// <summary>
/// Defines parameters for how to emit a particle, and when to emit it
/// </summary>
public class ConchplexBurstEmission
{
	/// <summary>
	/// Delay - what delay time to start bursting
	/// </summary>
	[Property, Group("Emitter"), KeyProperty]
	public float BurstDelay { get; set; } = 0f;

	/// <summary>
	/// Ammount - how many to emit
	/// </summary>
	[Property, Group("Emitter"), KeyProperty]
	[Range(0f, 1000f), Step(0.01f)]
	public float BurstAmmount { get; set; } = 10f;

	/// <summary>
	/// Duration - Timespan to evenly emit over
	/// </summary>
	[Property, Group("Emitter"), KeyProperty]
	public float BurstDuration { get; set; } = 0f;

	/// <summary>
	/// Probability - how likely it is to trigger 0 - never, 1 - always
	/// </summary>
	[Property, Group("Emitter"), KeyProperty]
	[Range(0f, 1f), Step(0.01f)]
	public float Probability { get; set; } = 1f;

	/// <summary>
	/// Cycles - how many times to try burst during a loop, 0 = infinite
	/// </summary>
	[Property, Group("Emitter"), KeyProperty]
	public int Cycles { get; set; } = 0;

	[Hide] private float timeSinceBurst = 0f;
	[Hide] private float carryOver = 0f;
	[Hide] private int totalEmitted = 0;
	[Hide] private bool burstPending;
	[Hide] private bool probablityChecked;
	[Hide] private bool probablityPassed;
	[Hide] private float burstDelta;
	[Hide] private int cyclesDone = 0;
	// DISTANCE EMISSION



	public bool TryEmit(ParticleEffect target, ConchplexEmitter emitter, float time)
	{
		if (!burstPending || !probablityPassed) return false;
		if (time - BurstDelay < 0) return false;
		if (cyclesDone >= Cycles && Cycles! < 0) return false;
		if(!probablityChecked)
		{
			probablityChecked = true;
			if (Game.Random.Float() > Probability)
			{
				probablityPassed = false;
				burstPending = false;
				return false;
			}
		}
		
		
		var enmitted = false;
		

		// Burst has started, start counting down the burst time
		burstDelta = ( timeSinceBurst + (time - BurstDelay)) - timeSinceBurst;
		timeSinceBurst += time - BurstDelay;
		
		// figure out how many to emit
		float emissionRate = (BurstDuration > 0) ? BurstAmmount / BurstDuration : 0;
		float particlesThisStep = emissionRate * burstDelta + carryOver - totalEmitted;
		carryOver = particlesThisStep - (int)particlesThisStep;


		// Burst time has ended, force ammount to emit, to whatever ammount remains
		if (time - BurstDelay >= BurstDuration || BurstDuration <= 0)
		{
			particlesThisStep = BurstAmmount - totalEmitted;
			burstPending = false;
			enmitted = true;
		}

		// emit particles specified this step
		for (int i = 0; i < (int)particlesThisStep; i++)
		{
			if (target.IsFull) break;
			totalEmitted++;
			emitter.EmitParticle(target);
		}
		cyclesDone++;
		return enmitted;
	}

	public bool TryEmit(ParticleEffect target, ConchplexEmitter[] emitter, float time)
	{
		if (!burstPending || !probablityPassed) return false;
		if (time - BurstDelay < 0) return false;
		if (cyclesDone >= Cycles && Cycles! < 0) return false;
		if (!probablityChecked)
		{
			probablityChecked = true;
			if (Game.Random.Float() > Probability)
			{
				probablityPassed = false;
				burstPending = false;
				return false;
			}
		}

		var enmitted = false;


		// Burst has started, start counting down the burst time
		burstDelta = (timeSinceBurst + (time - BurstDelay)) - timeSinceBurst;
		timeSinceBurst += time - BurstDelay;

		// figure out how many to emit
		float emissionRate = (BurstDuration > 0) ? BurstAmmount / BurstDuration : 0;
		float particlesThisStep = emissionRate * burstDelta + carryOver - totalEmitted;
		carryOver = particlesThisStep - (int)particlesThisStep;


		// Burst time has ended, force ammount to emit, to whatever ammount remains
		if (time - BurstDelay >= BurstDuration || BurstDuration <= 0)
		{
			particlesThisStep = BurstAmmount - totalEmitted;
			burstPending = false;
			enmitted = true;
		}

		// emit particles specified this step
		for (int i = 0; i < (int)particlesThisStep; i++)
		{
			if (target.IsFull) break;
			var randomEmitter = emitter[Game.Random.Int(0, emitter.Length - 1)];
			totalEmitted++;
			randomEmitter.EmitParticle(target);
		}
		cyclesDone++;
		return enmitted;
	}



	public bool IsActive() { return burstPending; }

	public void ResetEmission()
	{
		burstPending = true;
		probablityChecked = false;
		probablityPassed = true;
		timeSinceBurst = 0f;
		carryOver = 0f;
		totalEmitted = 0;
	}

	
}