Agenda/EnemyVariant.cs
namespace PlanetMeat;

public class EnemyVariant
{
	public static string GetDisplayName( string ident ) => "enemy." + ident + ".title";

	public string Ident
	{
		get;
		set
		{
			Prefab = GameObject.GetPrefab( "enemies/" + value + ".prefab" );
			field = value;
		}
	}

	public GameObject Prefab { get; private set; }
	public string ChallengeIdent => "add_" + Ident;
	public string DisplayName => GetDisplayName( Ident );

	public int SpawnSize { get; set; } = 1;
	public int SpawnCost { get; set; } = 1;
	public int WaveContributionPerLevel { get; set; } = 1;

	public int CurrentWaveContribution { get; private set; } = 0;
	public int GroupInterval { get; private set; } = 0;
	public bool InGroup => GroupInterval == 1 || IsPresent && elapsedGroups >= GroupInterval;
	public bool InSpawn => elapsedSpawns > SpawnCost;

	public bool IsPresent => GroupInterval != 0;

	private int elapsedGroups;
	private int elapsedSpawns;
	private bool wasInGroup = false;

	public EnemyVariant( string ident, bool isBase = false )
	{
		Ident = ident;
		GroupInterval = isBase ? -1 : 0;
	}

	public void BakeStats()
	{
		var challenge = ChallengeIdent;
		if ( challenge != "" )
		{
			var level = Difficulty.Current.GetChallengeLevel( challenge );
			if ( level > 0 )
			{
				var max = Difficulty.GetChallengeMax( challenge );
				GroupInterval = max - level + 1;
				CurrentWaveContribution = level * WaveContributionPerLevel;
			}
			else
			{
				GroupInterval = 0;
			}
		}
	}

	public void Spawn( Vector3 worldPosition, int amount = 1, bool fadeIn = false )
	{
		if ( Prefab.Components.Get<WaveTracked>( FindMode.EnabledInSelfAndDescendants ) is not null )
			Agenda.Current.NumActiveTracked += amount;

		for ( var i = 0; i < amount; i++ )
		{
			var go = Prefab.Clone( worldPosition );
			if ( !fadeIn && go.Components.Get<FadeIn>() is FadeIn fader )
				fader.Opacity = 1.0f;
		}
	}

	public void SpawnWithGroup( Vector3 worldPosition )
	{
		Spawn( worldPosition, SpawnSize, true );

		elapsedSpawns -= SpawnCost;
		wasInGroup = true;
	}

	public void BeginWave( int groupCount )
	{
		if ( GroupInterval > groupCount )
		{
			elapsedGroups = GroupInterval - Game.Random.Next( groupCount ) - 1;
		}
		else if ( GroupInterval > 0 )
		{
			var m = groupCount % GroupInterval;
			elapsedGroups = Game.Random.Next( GroupInterval - m ) + m;
		}
	}

	public void BeginGroup()
	{
		elapsedGroups++;
		wasInGroup = false;
		elapsedSpawns = SpawnCost;
	}

	public void OtherSpawned()
	{
		elapsedSpawns++;
	}

	public void EndGroup()
	{
		if ( wasInGroup )
			elapsedGroups -= GroupInterval;
	}
}