Decompiled source of RandomEnemyGenerator v2.0.1

RandomEnemyGenerator.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using DM;
using Landfall.TABS;
using Landfall.TABS.Budget;
using Landfall.TABS.GameMode;
using Landfall.TABS.UnitPlacement;
using Landfall.TABS.WinConditions;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("RandomEnemyGenerator")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("RandomEnemyGenerator")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("3737bb01-abc0-4c64-9e0c-2cf744d6c985")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace RandomEnemyGenerator;

public static class ArmyGenerator
{
	private sealed class LayoutEntry
	{
		public UnitBlueprint Blueprint;

		public int Cost;

		public float Width;

		public float Depth;

		public bool IsRanged;

		public bool IsLarge;
	}

	private sealed class PlacementArea
	{
		public Vector3 Center;

		public Vector3 Forward;

		public Vector3 Side;

		public float FrontF;

		public float BackF;

		public float MinS;

		public float MaxS;

		public float Y;
	}

	public static int Budget = 5000;

	public static string BudgetText = "5000";

	public static float UnitPadding = 0.8f;

	public static float PositionJitter = 0.4f;

	public static float FacingVariation = 8f;

	public static float SpawnHeightLift = 1.1f;

	public static bool ClearBeforeGenerate = true;

	public static bool IgnoreOfficialBudgetCap = true;

	public static bool RaiseOfficialBlueBudget = true;

	public static bool IncludeModdedCustomUnits = false;

	public static bool IncludeWipUnits = false;

	private static readonly Random Rng = new Random();

	public static int LastPlacedCount { get; private set; }

	public static int LastSpent { get; private set; }

	public static string LastMessage { get; private set; } = "Ready.";


	public static void SetStatus(string message)
	{
		LastMessage = message;
	}

	public static bool TryParseBudgetField()
	{
		if (!int.TryParse(BudgetText, out var result))
		{
			return false;
		}
		Budget = result;
		return true;
	}

	public static void AdjustBudget(int delta)
	{
		Budget = Mathf.Clamp(Budget + delta, 10, 50000);
		BudgetText = Budget.ToString();
	}

	public static int GetBlueBudgetUsed()
	{
		BattleBudget battleBudget = GetBattleBudget();
		if (battleBudget == null)
		{
			return 0;
		}
		try
		{
			return battleBudget.GetBudget((Team)1);
		}
		catch
		{
			return 0;
		}
	}

	public static int GetBlueBudgetMax()
	{
		BattleBudget battleBudget = GetBattleBudget();
		if (battleBudget == null)
		{
			return 0;
		}
		try
		{
			return battleBudget.GetMaxBudget((Team)1);
		}
		catch
		{
			return 0;
		}
	}

	public static int GetBlueBudgetRemaining()
	{
		BattleBudget battleBudget = GetBattleBudget();
		if (battleBudget == null)
		{
			return 0;
		}
		try
		{
			if (battleBudget.IsInfinite((Team)1))
			{
				return int.MaxValue;
			}
			int budget = battleBudget.GetBudget((Team)1);
			int maxBudget = battleBudget.GetMaxBudget((Team)1);
			return Mathf.Max(0, maxBudget - budget);
		}
		catch
		{
			return 0;
		}
	}

	public static void SyncBlueUI()
	{
		if ((Object)(object)PlacementUI.Instance == (Object)null)
		{
			return;
		}
		try
		{
			PlacementUI.Instance.SetBudgetText((Team)1, GetBlueBudgetUsed());
			PlacementUI.Instance.OnUnitCountChanged((Team)1);
		}
		catch
		{
		}
	}

	public static void Generate()
	{
		LastPlacedCount = 0;
		LastSpent = 0;
		LastMessage = "Generating...";
		if (!TryParseBudgetField())
		{
			LastMessage = "Budget field is invalid.";
			return;
		}
		Budget = Mathf.Clamp(Budget, 10, 50000);
		BudgetText = Budget.ToString();
		GameModeService service = ServiceLocator.GetService<GameModeService>();
		if ((Object)(object)service == (Object)null || service.CurrentGameMode == null)
		{
			LastMessage = "No active game mode.";
			return;
		}
		BaseGameMode currentGameMode = service.CurrentGameMode;
		if (currentGameMode.Brush == null || currentGameMode.BattleBudget == null)
		{
			LastMessage = "Placement brush or battle budget is missing.";
			return;
		}
		UnitDatabase.EnsureInitialized(IncludeModdedCustomUnits, IncludeWipUnits);
		if (UnitDatabase.Count == 0)
		{
			LastMessage = "No usable units found.";
			return;
		}
		if (ClearBeforeGenerate)
		{
			PlacementSpawner.ClearBlueArmy();
			SyncBlueUI();
		}
		BattleBudget battleBudget = currentGameMode.BattleBudget;
		int blueBudgetUsed = GetBlueBudgetUsed();
		int blueBudgetMax = GetBlueBudgetMax();
		bool flag = battleBudget.IsInfinite((Team)1);
		int num = (flag ? int.MaxValue : Mathf.Max(0, blueBudgetMax - blueBudgetUsed));
		if (!flag && Budget > num && (IgnoreOfficialBudgetCap || RaiseOfficialBlueBudget))
		{
			int num2 = blueBudgetUsed + Budget;
			battleBudget.SetBudget((Team)1, num2);
			num = GetBlueBudgetRemaining();
		}
		int num3 = (flag ? Budget : Mathf.Min(Budget, num));
		if (num3 <= 0)
		{
			LastMessage = "Blue side has no remaining budget to spend.";
			return;
		}
		int cheapestCost = UnitDatabase.GetCheapestCost();
		if (cheapestCost <= 0 || num3 < cheapestCost)
		{
			LastMessage = "Budget is below the cheapest usable unit.";
			return;
		}
		if (!TryBuildPlacementArea(currentGameMode.Brush, out var area))
		{
			LastMessage = "Could not find the real blue placement area on this map.";
			return;
		}
		List<UnitBlueprint> list = BuildArmy(num3);
		if (list.Count == 0)
		{
			LastMessage = "Could not assemble an army from the current budget.";
			return;
		}
		PlaceArmy(currentGameMode.Brush, area, list);
		SyncBlueUI();
		if (LastPlacedCount <= 0)
		{
			LastMessage = "Nothing was placed. The formation probably ran out of valid blue-side space.";
			return;
		}
		LastMessage = "Placed " + LastPlacedCount + " real blue placement units, spent " + LastSpent + ", blue used now " + GetBlueBudgetUsed() + ", remaining " + GetBlueBudgetRemaining() + ".";
	}

	private static BattleBudget GetBattleBudget()
	{
		GameModeService service = ServiceLocator.GetService<GameModeService>();
		if ((Object)(object)service == (Object)null || service.CurrentGameMode == null)
		{
			return null;
		}
		return service.CurrentGameMode.BattleBudget;
	}

	private static List<UnitBlueprint> BuildArmy(int workingBudget)
	{
		List<UnitBlueprint> list = new List<UnitBlueprint>();
		int remaining = workingBudget;
		int cheapestCost = UnitDatabase.GetCheapestCost();
		int num = 0;
		while (remaining >= cheapestCost && num < 5000)
		{
			List<UnitBlueprint> list2 = UnitDatabase.Units.Where((UnitBlueprint u) => (int)u.GetUnitCost(true) <= remaining).ToList();
			if (list2.Count == 0)
			{
				break;
			}
			UnitBlueprint val = PickWeightedAffordable(list2, remaining);
			if ((Object)(object)val == (Object)null)
			{
				break;
			}
			list.Add(val);
			remaining -= (int)val.GetUnitCost(true);
			num++;
		}
		return list;
	}

	private static UnitBlueprint PickWeightedAffordable(List<UnitBlueprint> affordable, int remaining)
	{
		float num = Mathf.Clamp((float)remaining * 0.08f, 70f, 1400f);
		float num2 = 0f;
		float[] array = new float[affordable.Count];
		for (int i = 0; i < affordable.Count; i++)
		{
			UnitBlueprint val = affordable[i];
			int unitCost = (int)val.GetUnitCost(true);
			float num3 = Mathf.Abs((float)unitCost - num) / Mathf.Max(1f, num);
			float num4 = 0.25f + 1f / (1f + num3) * 1.75f;
			num2 += (array[i] = ((!IsRanged(val)) ? (num4 * 1.1f) : (num4 * 0.9f)));
		}
		float num5 = (float)Rng.NextDouble() * num2;
		for (int j = 0; j < affordable.Count; j++)
		{
			num5 -= array[j];
			if (num5 <= 0f)
			{
				return affordable[j];
			}
		}
		return affordable[affordable.Count - 1];
	}

	private static void PlaceArmy(UnitPlacementBrush brush, PlacementArea area, List<UnitBlueprint> army)
	{
		//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0304: Unknown result type (might be due to invalid IL or missing references)
		//IL_0309: Unknown result type (might be due to invalid IL or missing references)
		//IL_030f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0319: Unknown result type (might be due to invalid IL or missing references)
		//IL_031e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0323: Unknown result type (might be due to invalid IL or missing references)
		//IL_0365: Unknown result type (might be due to invalid IL or missing references)
		//IL_036a: Unknown result type (might be due to invalid IL or missing references)
		//IL_036f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0380: Unknown result type (might be due to invalid IL or missing references)
		//IL_0385: Unknown result type (might be due to invalid IL or missing references)
		//IL_038a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0393: Unknown result type (might be due to invalid IL or missing references)
		//IL_0395: Unknown result type (might be due to invalid IL or missing references)
		List<LayoutEntry> list = new List<LayoutEntry>();
		for (int i = 0; i < army.Count; i++)
		{
			UnitBlueprint val = army[i];
			EstimateFootprint(val, out var width, out var depth);
			list.Add(new LayoutEntry
			{
				Blueprint = val,
				Cost = (int)val.GetUnitCost(true),
				Width = width,
				Depth = depth,
				IsRanged = IsRanged(val),
				IsLarge = (depth >= 3.2f || width >= 3.2f || (Object)(object)val.Mount != (Object)null)
			});
		}
		List<LayoutEntry> entries = (from e in list
			where !e.IsRanged
			orderby e.IsLarge descending, e.Cost descending
			select e).ToList();
		List<LayoutEntry> entries2 = (from e in list
			where e.IsRanged
			orderby e.Cost descending
			select e).ToList();
		float maxWidth = Mathf.Max(8f, area.MaxS - area.MinS - 2.5f);
		List<List<LayoutEntry>> list2 = new List<List<LayoutEntry>>();
		list2.AddRange(PackRows(entries, maxWidth));
		list2.AddRange(PackRows(entries2, maxWidth));
		float num = 2.2f;
		float num2 = 1.8f;
		float num3 = 1.2f;
		float num4 = area.FrontF - num;
		for (int j = 0; j < list2.Count; j++)
		{
			List<LayoutEntry> list3 = CenterOutOrder(list2[j]);
			float num5 = 0f;
			float num6 = 0f;
			for (int k = 0; k < list3.Count; k++)
			{
				num5 = Mathf.Max(num5, list3[k].Depth);
				num6 += list3[k].Width;
			}
			float num7 = num4 - num5 * 0.5f;
			if (num7 - num5 * 0.5f < area.BackF + num2)
			{
				break;
			}
			float num8 = (0f - num6) * 0.5f;
			num8 = Mathf.Clamp(num8, area.MinS + num3, area.MaxS - num3 - num6);
			float num9 = num8;
			for (int l = 0; l < list3.Count; l++)
			{
				LayoutEntry layoutEntry = list3[l];
				float num10 = num9 + layoutEntry.Width * 0.5f;
				num9 += layoutEntry.Width;
				float num11 = Random.Range(0f - PositionJitter, PositionJitter) * 0.35f;
				float num12 = Random.Range(0f - PositionJitter, PositionJitter);
				Vector3 position = area.Center + area.Forward * (num7 + num11) + area.Side * (num10 + num12);
				if (SnapIntoBlueArea(brush, area, ref position))
				{
					position.y = area.Y + GetSpawnLift(layoutEntry);
					float num13 = Random.Range(0f - FacingVariation, FacingVariation);
					Quaternion rotation = Quaternion.LookRotation(area.Forward, Vector3.up) * Quaternion.Euler(0f, num13, 0f);
					if (PlacementSpawner.PlaceUnit(layoutEntry.Blueprint, position, rotation))
					{
						LastPlacedCount++;
						LastSpent += layoutEntry.Cost;
					}
				}
			}
			num4 = num7 - num5 * 0.5f - UnitPadding;
		}
	}

	private static float GetSpawnLift(LayoutEntry entry)
	{
		float num = Mathf.Max(0.7f, entry.Depth * 0.45f);
		if (entry.IsLarge)
		{
			num += 0.35f;
		}
		num += SpawnHeightLift;
		return Mathf.Clamp(num, 0.8f, 3.5f);
	}

	private static List<List<LayoutEntry>> PackRows(List<LayoutEntry> entries, float maxWidth)
	{
		List<List<LayoutEntry>> list = new List<List<LayoutEntry>>();
		if (entries.Count == 0)
		{
			return list;
		}
		List<LayoutEntry> list2 = new List<LayoutEntry>();
		float num = 0f;
		for (int i = 0; i < entries.Count; i++)
		{
			LayoutEntry layoutEntry = entries[i];
			if (list2.Count > 0 && num + layoutEntry.Width > maxWidth)
			{
				list.Add(list2);
				list2 = new List<LayoutEntry>();
				num = 0f;
			}
			list2.Add(layoutEntry);
			num += layoutEntry.Width;
		}
		if (list2.Count > 0)
		{
			list.Add(list2);
		}
		return list;
	}

	private static List<LayoutEntry> CenterOutOrder(List<LayoutEntry> source)
	{
		List<LayoutEntry> list = (from e in source
			orderby e.IsLarge descending, e.Cost descending, e.Depth descending
			select e).ToList();
		List<LayoutEntry> list2 = new List<LayoutEntry>();
		bool flag = true;
		for (int i = 0; i < list.Count; i++)
		{
			if (flag)
			{
				list2.Insert(0, list[i]);
			}
			else
			{
				list2.Add(list[i]);
			}
			flag = !flag;
		}
		return list2;
	}

	private static bool TryBuildPlacementArea(UnitPlacementBrush brush, out PlacementArea area)
	{
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_0106: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//IL_011b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Invalid comparison between Unknown and I4
		//IL_012d: Unknown result type (might be due to invalid IL or missing references)
		//IL_012f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0131: Unknown result type (might be due to invalid IL or missing references)
		//IL_0132: Unknown result type (might be due to invalid IL or missing references)
		//IL_0137: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Invalid comparison between Unknown and I4
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_016a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0177: Unknown result type (might be due to invalid IL or missing references)
		//IL_017e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0183: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: Unknown result type (might be due to invalid IL or missing references)
		//IL_018c: Unknown result type (might be due to invalid IL or missing references)
		//IL_015a: Unknown result type (might be due to invalid IL or missing references)
		//IL_015f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0234: Unknown result type (might be due to invalid IL or missing references)
		//IL_0235: Unknown result type (might be due to invalid IL or missing references)
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_023d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0245: Unknown result type (might be due to invalid IL or missing references)
		//IL_026b: Unknown result type (might be due to invalid IL or missing references)
		area = null;
		MethodInfo teamAreaMethod = GetTeamAreaMethod(brush);
		if (teamAreaMethod == null)
		{
			Plugin.LogWarning("Could not reflect GetTeamAreaAtPosition from the brush behaviour.");
			return false;
		}
		List<Vector3> list = new List<Vector3>();
		List<Vector3> list2 = new List<Vector3>();
		Vector3 val = default(Vector3);
		for (float num = -70f; num <= 70f; num += 2.5f)
		{
			for (float num2 = -70f; num2 <= 70f; num2 += 2.5f)
			{
				((Vector3)(ref val))..ctor(num, 0.2f, num2);
				if (TryGetTeamAtPoint(teamAreaMethod, brush.BrushBehaviour, val, out var team, out var _))
				{
					if ((int)team == 1)
					{
						list.Add(val);
					}
					else if ((int)team == 0)
					{
						list2.Add(val);
					}
				}
			}
		}
		if (list.Count < 8)
		{
			return false;
		}
		Vector3 val2 = Average(list);
		Vector3 val3 = ((list2.Count > 0) ? Average(list2) : (val2 + Vector3.left * 10f));
		Vector3 val4 = val3 - val2;
		val4.y = 0f;
		if (((Vector3)(ref val4)).sqrMagnitude < 0.001f)
		{
			val4 = Vector3.left;
		}
		((Vector3)(ref val4)).Normalize();
		Vector3 val5 = new Vector3(0f - val4.z, 0f, val4.x);
		Vector3 normalized = ((Vector3)(ref val5)).normalized;
		float num3 = float.MinValue;
		float num4 = float.MaxValue;
		float num5 = float.MaxValue;
		float num6 = float.MinValue;
		for (int i = 0; i < list.Count; i++)
		{
			Vector3 val6 = list[i] - val2;
			float num7 = Vector3.Dot(val6, val4);
			float num8 = Vector3.Dot(val6, normalized);
			if (num7 > num3)
			{
				num3 = num7;
			}
			if (num7 < num4)
			{
				num4 = num7;
			}
			if (num8 < num5)
			{
				num5 = num8;
			}
			if (num8 > num6)
			{
				num6 = num8;
			}
		}
		area = new PlacementArea
		{
			Center = val2,
			Forward = val4,
			Side = normalized,
			FrontF = num3,
			BackF = num4,
			MinS = num5,
			MaxS = num6,
			Y = val2.y
		};
		return true;
	}

	private static bool SnapIntoBlueArea(UnitPlacementBrush brush, PlacementArea area, ref Vector3 position)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Invalid comparison between Unknown and I4
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Invalid comparison between Unknown and I4
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		MethodInfo teamAreaMethod = GetTeamAreaMethod(brush);
		if (teamAreaMethod == null)
		{
			return true;
		}
		if (TryGetTeamAtPoint(teamAreaMethod, brush.BrushBehaviour, position, out var team, out var rotation) && (int)team == 1)
		{
			return true;
		}
		for (int i = 1; i <= 18; i++)
		{
			float num = 0.55f * (float)i;
			Vector3 val = position - area.Forward * num;
			val += area.Side * Random.Range(-0.35f, 0.35f);
			if (TryGetTeamAtPoint(teamAreaMethod, brush.BrushBehaviour, val, out team, out rotation) && (int)team == 1)
			{
				position = val;
				return true;
			}
		}
		return false;
	}

	private static MethodInfo GetTeamAreaMethod(UnitPlacementBrush brush)
	{
		if (brush == null || brush.BrushBehaviour == null)
		{
			return null;
		}
		return ((object)brush.BrushBehaviour).GetType().GetMethod("GetTeamAreaAtPosition", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
	}

	private static bool TryGetTeamAtPoint(MethodInfo method, object brushBehaviour, Vector3 point, out Team team, out Quaternion rotation)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Expected I4, but got Unknown
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		team = (Team)0;
		rotation = Quaternion.identity;
		try
		{
			object[] array = new object[2]
			{
				point,
				Quaternion.identity
			};
			object obj = method.Invoke(brushBehaviour, array);
			if (obj is Team)
			{
				team = (Team)(int)(Team)obj;
				rotation = (Quaternion)array[1];
				return true;
			}
		}
		catch
		{
		}
		return false;
	}

	private static Vector3 Average(List<Vector3> points)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = Vector3.zero;
		for (int i = 0; i < points.Count; i++)
		{
			val += points[i];
		}
		return val / (float)Mathf.Max(1, points.Count);
	}

	private static void EstimateFootprint(UnitBlueprint blueprint, out float width, out float depth)
	{
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		width = 2.2f;
		depth = 2.2f;
		try
		{
			if ((Object)(object)blueprint != (Object)null && (Object)(object)blueprint.UnitBase != (Object)null)
			{
				Unit component = blueprint.UnitBase.GetComponent<Unit>();
				if ((Object)(object)component != (Object)null)
				{
					PlacementSquare placementSquare = component.PlacementSquare;
					Vector3 size = ((PlacementSquare)(ref placementSquare)).Size;
					width = Mathf.Max(1.4f, Mathf.Abs(size.x)) + UnitPadding;
					depth = Mathf.Max(1.4f, Mathf.Abs(size.z)) + UnitPadding;
					return;
				}
			}
		}
		catch
		{
		}
		int num = (int)(((Object)(object)blueprint != (Object)null) ? blueprint.GetUnitCost(true) : 100);
		float num2 = Mathf.Clamp((float)num / 350f, 1.8f, 4.8f);
		width = num2 + UnitPadding * 0.5f;
		depth = num2 + UnitPadding * 0.5f;
	}

	private static bool IsRanged(UnitBlueprint blueprint)
	{
		if ((Object)(object)blueprint == (Object)null)
		{
			return false;
		}
		try
		{
			if ((Object)(object)blueprint.RightWeapon != (Object)null && (Object)(object)blueprint.RightWeapon.GetComponent<RangeWeapon>() != (Object)null)
			{
				return true;
			}
			if ((Object)(object)blueprint.LeftWeapon != (Object)null && (Object)(object)blueprint.LeftWeapon.GetComponent<RangeWeapon>() != (Object)null)
			{
				return true;
			}
		}
		catch
		{
		}
		return false;
	}
}
public static class PlacementSpawner
{
	public static bool PlaceUnit(UnitBlueprint blueprint, Vector3 position, Quaternion rotation)
	{
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)blueprint == (Object)null)
		{
			return false;
		}
		GameModeService service = ServiceLocator.GetService<GameModeService>();
		if ((Object)(object)service == (Object)null || service.CurrentGameMode == null)
		{
			return false;
		}
		BaseGameMode currentGameMode = service.CurrentGameMode;
		UnitPlacementBrush brush = currentGameMode.Brush;
		if (brush == null)
		{
			return false;
		}
		int bluePlacedCount = GetBluePlacedCount();
		try
		{
			brush.PlaceUnitInternal(blueprint, (Team)1, position, rotation, true, (RuntimeReference)null, true, false, true, 0);
		}
		catch (Exception ex)
		{
			Plugin.LogWarning("Placement failed for " + blueprint.Name + ": " + ex.Message);
			return false;
		}
		int bluePlacedCount2 = GetBluePlacedCount();
		return bluePlacedCount2 > bluePlacedCount;
	}

	public static void ClearBlueArmy()
	{
		if ((Object)(object)PlacementUI.Instance != (Object)null)
		{
			PlacementUI.Instance.ClearBlue();
			return;
		}
		GameModeService service = ServiceLocator.GetService<GameModeService>();
		if ((Object)(object)service != (Object)null && service.CurrentGameMode != null)
		{
			service.CurrentGameMode.OnClearedTeam((Team)1);
		}
	}

	public static int GetBluePlacedCount()
	{
		GameModeService service = ServiceLocator.GetService<GameModeService>();
		if ((Object)(object)service == (Object)null || service.CurrentGameMode == null)
		{
			return 0;
		}
		BaseGameMode currentGameMode = service.CurrentGameMode;
		if (currentGameMode.TeamLayouts == null)
		{
			return 0;
		}
		return currentGameMode.TeamLayouts.GetTeamLayout((Team)1).Count;
	}

	public static void StartBattle()
	{
		if ((Object)(object)PlacementUI.Instance != (Object)null)
		{
			PlacementUI.Instance.StartBattle();
		}
	}

	public static void BackToPlacement()
	{
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Invalid comparison between Unknown and I4
		GameModeService service = ServiceLocator.GetService<GameModeService>();
		if (!((Object)(object)service == (Object)null) && service.CurrentGameMode != null)
		{
			BaseGameMode currentGameMode = service.CurrentGameMode;
			if (currentGameMode.GameStateManager != null && (int)currentGameMode.GameStateManager.GameState == 1)
			{
				currentGameMode.GameStateManager.EnterPlacementState();
			}
		}
	}
}
[BepInPlugin("com.randomenemygenerator.fullmod", "Random Enemy Generator", "3.0.0")]
public sealed class Plugin : BaseUnityPlugin
{
	internal static Plugin Instance;

	private GameObject uiRoot;

	private void Awake()
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Expected O, but got Unknown
		Instance = this;
		uiRoot = new GameObject("RandomEnemyGenerator_UI");
		((Object)uiRoot).hideFlags = (HideFlags)1;
		Object.DontDestroyOnLoad((Object)(object)uiRoot);
		uiRoot.AddComponent<UIManager.UIBehaviour>();
		UnitDatabase.MarkDirty();
		LogInfo("Random Enemy Generator loaded.");
	}

	private void OnDestroy()
	{
		if ((Object)(object)uiRoot != (Object)null)
		{
			Object.Destroy((Object)(object)uiRoot);
			uiRoot = null;
		}
		if ((Object)(object)Instance == (Object)(object)this)
		{
			Instance = null;
		}
	}

	internal static void LogInfo(string message)
	{
		if ((Object)(object)Instance != (Object)null)
		{
			((BaseUnityPlugin)Instance).Logger.LogInfo((object)message);
		}
	}

	internal static void LogWarning(string message)
	{
		if ((Object)(object)Instance != (Object)null)
		{
			((BaseUnityPlugin)Instance).Logger.LogWarning((object)message);
		}
	}

	internal static void LogError(string message)
	{
		if ((Object)(object)Instance != (Object)null)
		{
			((BaseUnityPlugin)Instance).Logger.LogError((object)message);
		}
	}
}
public static class UIManager
{
	public sealed class UIBehaviour : MonoBehaviour
	{
		private Rect windowRect = new Rect(18f, 18f, 390f, 560f);

		private Vector2 scroll;

		private bool visible = true;

		private bool blockingGameInput;

		private void Update()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown((KeyCode)287))
			{
				visible = !visible;
			}
			bool flag = visible && ((Rect)(ref windowRect)).Contains(GetMouseGuiPosition());
			bool flag2 = blockingGameInput && Input.GetMouseButton(0);
			SetGameInputBlocked(flag || flag2);
		}

		private void OnDisable()
		{
			SetGameInputBlocked(blocked: false);
		}

		private void OnDestroy()
		{
			SetGameInputBlocked(blocked: false);
		}

		private void OnGUI()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Invalid comparison between Unknown and I4
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Invalid comparison between Unknown and I4
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Invalid comparison between Unknown and I4
			if (!visible)
			{
				SetGameInputBlocked(blocked: false);
				return;
			}
			GUI.depth = -1000;
			windowRect = GUI.Window(684213, windowRect, new WindowFunction(DrawWindow), "Random Enemy Generator");
			Event current = Event.current;
			if (current != null && ((Rect)(ref windowRect)).Contains(GetMouseGuiPosition()) && ((int)current.type == 0 || (int)current.type == 1 || (int)current.type == 3 || (int)current.type == 6))
			{
				current.Use();
			}
		}

		private void DrawWindow(int id)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_058c: Unknown result type (might be due to invalid IL or missing references)
			scroll = GUILayout.BeginScrollView(scroll, false, true, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(380f),
				GUILayout.Height(525f)
			});
			GUILayout.Label("F6 = show / hide", Array.Empty<GUILayoutOption>());
			GUILayout.Space(6f);
			GUILayout.Label("Requested spend", Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			ArmyGenerator.BudgetText = GUILayout.TextField(ArmyGenerator.BudgetText, 10, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) });
			if (GUILayout.Button("-500", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }))
			{
				ArmyGenerator.AdjustBudget(-500);
			}
			if (GUILayout.Button("+500", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }))
			{
				ArmyGenerator.AdjustBudget(500);
			}
			if (GUILayout.Button("+5000", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }))
			{
				ArmyGenerator.AdjustBudget(5000);
			}
			GUILayout.EndHorizontal();
			ArmyGenerator.Budget = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)ArmyGenerator.Budget, 10f, 50000f, Array.Empty<GUILayoutOption>()));
			if (ArmyGenerator.TryParseBudgetField())
			{
				ArmyGenerator.Budget = Mathf.Clamp(ArmyGenerator.Budget, 10, 50000);
				ArmyGenerator.BudgetText = ArmyGenerator.Budget.ToString();
			}
			else
			{
				ArmyGenerator.BudgetText = ArmyGenerator.Budget.ToString();
			}
			GUILayout.Label("Requested spend: " + ArmyGenerator.Budget, Array.Empty<GUILayoutOption>());
			GUILayout.Label("Blue spent now: " + ArmyGenerator.GetBlueBudgetUsed(), Array.Empty<GUILayoutOption>());
			GUILayout.Label("Blue max budget: " + ArmyGenerator.GetBlueBudgetMax(), Array.Empty<GUILayoutOption>());
			GUILayout.Label("Blue remaining cap: " + ArmyGenerator.GetBlueBudgetRemaining(), Array.Empty<GUILayoutOption>());
			GUILayout.Space(10f);
			ArmyGenerator.UnitPadding = SliderLine("Unit padding", ArmyGenerator.UnitPadding, 0.2f, 2.5f);
			ArmyGenerator.PositionJitter = SliderLine("Position jitter", ArmyGenerator.PositionJitter, 0f, 1.5f);
			ArmyGenerator.FacingVariation = SliderLine("Facing variation", ArmyGenerator.FacingVariation, 0f, 20f);
			ArmyGenerator.SpawnHeightLift = SliderLine("Spawn height lift", ArmyGenerator.SpawnHeightLift, 0.3f, 3f);
			GUILayout.Space(8f);
			GUILayout.Label("Options", Array.Empty<GUILayoutOption>());
			ArmyGenerator.ClearBeforeGenerate = GUILayout.Toggle(ArmyGenerator.ClearBeforeGenerate, "Clear current blue army first", Array.Empty<GUILayoutOption>());
			ArmyGenerator.IgnoreOfficialBudgetCap = GUILayout.Toggle(ArmyGenerator.IgnoreOfficialBudgetCap, "Ignore official TABS blue budget cap", Array.Empty<GUILayoutOption>());
			ArmyGenerator.RaiseOfficialBlueBudget = GUILayout.Toggle(ArmyGenerator.RaiseOfficialBlueBudget, "Also try to raise official blue budget", Array.Empty<GUILayoutOption>());
			ArmyGenerator.IncludeModdedCustomUnits = GUILayout.Toggle(ArmyGenerator.IncludeModdedCustomUnits, "Include modded/custom units", Array.Empty<GUILayoutOption>());
			ArmyGenerator.IncludeWipUnits = GUILayout.Toggle(ArmyGenerator.IncludeWipUnits, "Include WIP units (unstable)", Array.Empty<GUILayoutOption>());
			GUILayout.Space(10f);
			GUILayout.Label("Actions", Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Generate Blue Army", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
			{
				ArmyGenerator.Generate();
			}
			if (GUILayout.Button("Clear Blue Army", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f) }))
			{
				PlacementSpawner.ClearBlueArmy();
				ArmyGenerator.SyncBlueUI();
				ArmyGenerator.SetStatus("Cleared blue army.");
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Reload Unit Database", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) }))
			{
				UnitDatabase.MarkDirty();
				UnitDatabase.EnsureInitialized(ArmyGenerator.IncludeModdedCustomUnits, ArmyGenerator.IncludeWipUnits);
				ArmyGenerator.SetStatus("Reloaded unit database.");
			}
			if (GUILayout.Button("Sync Blue UI", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) }))
			{
				ArmyGenerator.SyncBlueUI();
				ArmyGenerator.SetStatus("Blue UI synced.");
			}
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Start Battle", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) }))
			{
				PlacementSpawner.StartBattle();
			}
			if (GUILayout.Button("Back To Placement", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) }))
			{
				PlacementSpawner.BackToPlacement();
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(10f);
			GUILayout.Label("Status", Array.Empty<GUILayoutOption>());
			GUILayout.Space(4f);
			GUILayout.Label("Usable units loaded: " + UnitDatabase.Count, Array.Empty<GUILayoutOption>());
			GUILayout.Label("Current blue placed units: " + PlacementSpawner.GetBluePlacedCount(), Array.Empty<GUILayoutOption>());
			GUILayout.Label("Last generated units: " + ArmyGenerator.LastPlacedCount, Array.Empty<GUILayoutOption>());
			GUILayout.Label("Last spent: " + ArmyGenerator.LastSpent, Array.Empty<GUILayoutOption>());
			GUILayout.TextArea(ArmyGenerator.LastMessage, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(120f) });
			GUILayout.EndScrollView();
			GUI.DragWindow(new Rect(0f, 0f, 10000f, 22f));
		}

		private float SliderLine(string label, float value, float min, float max)
		{
			GUILayout.Label(label + ": " + value.ToString("0.0"), Array.Empty<GUILayoutOption>());
			return GUILayout.HorizontalSlider(value, min, max, Array.Empty<GUILayoutOption>());
		}

		private static Vector2 GetMouseGuiPosition()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			Vector3 mousePosition = Input.mousePosition;
			return new Vector2(mousePosition.x, (float)Screen.height - mousePosition.y);
		}

		private void SetGameInputBlocked(bool blocked)
		{
			if (blockingGameInput != blocked)
			{
				blockingGameInput = blocked;
				UIScreenInputBlocker.DoBlockInput(blocked);
			}
		}
	}
}
public static class UnitDatabase
{
	private static bool initialized;

	private static bool includeModdedCustomUnits;

	private static bool includeWipUnits;

	public static List<UnitBlueprint> Units { get; private set; } = new List<UnitBlueprint>();


	public static int Count => (Units != null) ? Units.Count : 0;

	public static void MarkDirty()
	{
		initialized = false;
		Units.Clear();
	}

	public static void EnsureInitialized(bool includeModded, bool includeWip)
	{
		if (!initialized || includeModdedCustomUnits != includeModded || includeWipUnits != includeWip || Units.Count <= 0)
		{
			includeModdedCustomUnits = includeModded;
			includeWipUnits = includeWip;
			Initialize();
		}
	}

	public static void Initialize()
	{
		//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		initialized = true;
		Units = new List<UnitBlueprint>();
		ContentDatabase val;
		try
		{
			val = ContentDatabase.Instance();
		}
		catch (Exception ex)
		{
			Plugin.LogWarning("ContentDatabase not ready: " + ex.Message);
			initialized = false;
			return;
		}
		if (val == null)
		{
			initialized = false;
			return;
		}
		HashSet<string> hashSet = new HashSet<string>();
		IEnumerable<Faction> allFactions = val.GetAllFactions();
		if (allFactions == null)
		{
			initialized = false;
			return;
		}
		foreach (Faction item2 in allFactions)
		{
			if ((Object)(object)item2 == (Object)null || item2.Units == null)
			{
				continue;
			}
			UnitBlueprint[] units = item2.Units;
			foreach (UnitBlueprint val2 in units)
			{
				if (IsUsable(val2))
				{
					DatabaseID gUID = val2.Entity.GUID;
					string item = ((object)(DatabaseID)(ref gUID)).ToString();
					if (hashSet.Add(item))
					{
						Units.Add(val2);
					}
				}
			}
		}
		Units = (from u in Units
			orderby (int)u.GetUnitCost(true), u.Name
			select u).ToList();
		Plugin.LogInfo("Loaded usable units: " + Units.Count);
	}

	public static int GetCheapestCost()
	{
		if (Units == null || Units.Count == 0)
		{
			return 0;
		}
		return (int)Units[0].GetUnitCost(true);
	}

	private static bool IsUsable(UnitBlueprint unit)
	{
		if ((Object)(object)unit == (Object)null)
		{
			return false;
		}
		if (unit.Entity == null)
		{
			return false;
		}
		if ((Object)(object)unit.UnitBase == (Object)null)
		{
			return false;
		}
		if ((Object)(object)unit.UnitBase.GetComponent<Unit>() == (Object)null)
		{
			return false;
		}
		if (unit.IsSecret)
		{
			return false;
		}
		if (unit.ExcludeFromOnlineMultiplayer)
		{
			return false;
		}
		if (unit.HasMissingComponents)
		{
			return false;
		}
		if (!includeModdedCustomUnits && (unit.IsModUnit || unit.IsCustomUnit))
		{
			return false;
		}
		string text = ((unit.Entity.Name ?? string.Empty) + " " + (unit.Name ?? string.Empty) + " " + (unit.UnitDescription ?? string.Empty)).ToUpperInvariant();
		if (!includeWipUnits && text.Contains("WIP"))
		{
			return false;
		}
		if (text.Contains("DEBUG"))
		{
			return false;
		}
		if (text.Contains("PLACEHOLDER"))
		{
			return false;
		}
		if (text.Contains("TEST"))
		{
			return false;
		}
		int unitCost;
		try
		{
			unitCost = (int)unit.GetUnitCost(true);
		}
		catch
		{
			return false;
		}
		if (unitCost <= 0)
		{
			return false;
		}
		return true;
	}
}