Agenda/ScoutReport.cs
using System;

namespace PlanetMeat;

public struct ScoutReport()
{
	public string hpText;
	public string moveText;
	public string attackSpeedText;
	public string dmgText;

	public int groupCount;
	public readonly string GroupCountText => groupCount.ToString();

	public float groupDelay;
	public readonly string GroupDelayText => groupDelay.ToAutoDecimalString();

	public int groupSizeMin;
	public int groupSizeMax;
	public float groupSizeDebt;
	public readonly string GroupSizeText => GetValueText( groupSizeMin, groupSizeMax );

	public float groupSpread;
	public readonly string GroupSpreadText => groupSpread.ToAutoDecimalString();

	public int totalUnits;
	public readonly string TotalUnitsText => totalUnits.ToString();

	private static string GetValueText( int min, int max )
	{
		if ( min == max )
			return max.ToString();
		return min + "-" + max;
	}

	private static string AppendValue( string s, string a )
	{
		if ( s.Length > 0 )
			s += " · ";
		return s + a;
	}
	private static string AppendValue( string s, int a, int b ) => AppendValue( s, GetValueText( a, b ) );
	private static string AppendValue( string s, float a, float b ) => AppendValue( s, (int)MathF.Round( a ), (int)MathF.Round( b ) );

	public ScoutReport( IEnumerable<EnemyVariant> variants ) : this()
	{
		var variantContributions = 0.0f;

		var listDmg = "";
		var listAttackSpeed = "";
		var listHealth = "";
		var listMove = "";
		foreach ( var v in variants )
		{
			variantContributions += v.CurrentWaveContribution;

			if ( v.Prefab.Components.Get<EnemyChallengeReceiver>() is EnemyChallengeReceiver receiver )
			{
				receiver.Bake();

				listDmg = AppendValue( listDmg, receiver.MinDamage, receiver.MaxDamage );
				listAttackSpeed = AppendValue( listAttackSpeed, receiver.MinAttackSpeed, receiver.MaxAttackSpeed );
				listHealth = AppendValue( listHealth, receiver.MaxHp.ToString() );
				listMove = AppendValue( listMove, Math.Round( receiver.MoveSpeed ).ToString( "N0" ) );
			}
		}
		dmgText = listDmg;
		attackSpeedText = listAttackSpeed;
		hpText = listHealth;
		moveText = listMove;

		var roundNum = Agenda.Current.RoundNum;
		var waveNum = Agenda.Current.WaveNum;

		var isHydra = Difficulty.Current.HasChallenge( "hydra" );
		var groupCountRaw = roundNum * 1.5f + waveNum * 0.3f * Difficulty.Current.GetMult( "GroupCount" );
		groupCountRaw += variantContributions > 0.5f ? (groupCountRaw * variantContributions * 0.01f) : 0.0f;
		if ( isHydra )
			groupCountRaw *= 0.6f;
		groupCount = (int)Math.Ceiling( groupCountRaw );

		var groupSize = roundNum * 1.25f + waveNum * 0.3f * Difficulty.Current.GetMult( "GroupSize" );
		if ( isHydra )
			groupSize *= 0.6f;
		groupSizeMin = Math.Max( 1, (int)MathF.Floor( groupSize ) );
		groupSizeDebt = groupSize - groupSizeMin;
		groupSizeMax = (int)MathF.Ceiling( groupSize );

		groupDelay = 1.1f * Difficulty.Current.GetMult( "GroupDelay" ) / (0.25f * roundNum + 0.05f * waveNum);
		groupSpread = 15.0f * Difficulty.Current.GetMult( "GroupSpread" );

		totalUnits = 0;
		foreach ( var size in Agenda.GetGroupSizes( groupSizeDebt, groupCount, groupSizeMin ) )
			totalUnits += size;
	}
}