Decompiled source of RadsMoons v1.0.1

BepInEx/plugins/RadsMoons/RadsMoons.dll

Decompiled 14 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("RadsMoons")]
[assembly: AssemblyDescription("Asset-free custom moon rules for Lethal Company v81")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace RadsMoons
{
	internal static class Atmosphere
	{
		private static GameObject s_obj;

		private static VolumeProfile s_profile;

		internal static void Apply()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			Clear();
			string moon = Content.Moon;
			if (moon != "March" && moon != "Rend")
			{
				return;
			}
			s_obj = new GameObject("RadsMoons Fog");
			Volume[] array = Object.FindObjectsOfType<Volume>();
			Volume[] array2 = array;
			foreach (Volume val in array2)
			{
				if (val.isGlobal)
				{
					s_obj.layer = ((Component)val).gameObject.layer;
					break;
				}
			}
			Volume val2 = s_obj.AddComponent<Volume>();
			val2.isGlobal = true;
			val2.priority = 10000f;
			val2.weight = 1f;
			s_profile = ScriptableObject.CreateInstance<VolumeProfile>();
			val2.sharedProfile = s_profile;
			Fog val3 = s_profile.Add<Fog>(true);
			((VolumeParameter<bool>)(object)val3.enabled).Override(moon == "March");
			if (moon == "March")
			{
				((VolumeParameter<bool>)(object)val3.enableVolumetricFog).Override(true);
				((VolumeParameter<float>)(object)val3.meanFreePath).Override(20f);
				((VolumeParameter<float>)(object)val3.baseHeight).Override(10000f);
				((VolumeParameter<float>)(object)val3.maximumHeight).Override(10001f);
			}
		}

		internal static void Clear()
		{
			if ((Object)(object)s_obj != (Object)null)
			{
				Object.Destroy((Object)(object)s_obj);
			}
			if ((Object)(object)s_profile != (Object)null)
			{
				Object.Destroy((Object)(object)s_profile);
			}
			s_obj = null;
			s_profile = null;
		}
	}
	[HarmonyPatch(typeof(RoundManager), "SpawnEnemyFromVent")]
	internal static class CadaverBloomSpawnPatch
	{
		private static void Prefix(RoundManager __instance, out int __state)
		{
			__state = __instance.SpawnedEnemies.Count;
		}

		private static void Postfix(RoundManager __instance, int __state)
		{
			//IL_0053: 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)
			if (!((NetworkBehaviour)__instance).IsServer || !Levels.s_ready || Content.Moon != "Adamance")
			{
				return;
			}
			for (int i = __state; i < __instance.SpawnedEnemies.Count; i++)
			{
				EnemyAI obj = __instance.SpawnedEnemies[i];
				CadaverBloomAI val = (CadaverBloomAI)(object)((obj is CadaverBloomAI) ? obj : null);
				if (val != null)
				{
					((MonoBehaviour)Plugin.Instance).StartCoroutine(Activate(val, ((Component)val).transform.position, ((Component)val).transform.eulerAngles));
				}
			}
		}

		private static IEnumerator Activate(CadaverBloomAI bloom, Vector3 position, Vector3 rotation)
		{
			//IL_000e: 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_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			int generation = Landings.Generation;
			yield return (object)new WaitForSeconds(0.2f);
			if (generation != Landings.Generation || (Object)(object)bloom == (Object)null || !((NetworkBehaviour)bloom).IsSpawned || ((EnemyAI)bloom).isEnemyDead || bloom.hasBurst)
			{
				yield break;
			}
			PlayerControllerB[] players = StartOfRound.Instance.allPlayerScripts;
			for (int index = 0; index < players.Length; index++)
			{
				if (players[index].isPlayerControlled && !players[index].isPlayerDead)
				{
					EnemyEvents.Send(1, (EnemyAI)(object)bloom, index, position, rotation);
					break;
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class AttackScope
	{
		[ThreadStatic]
		internal static EnemyAI t_attacker;

		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return AccessTools.Method(typeof(PufferAI), "OnCollideWithPlayer", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(HoarderBugAI), "OnCollideWithPlayer", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(BaboonBirdAI), "OnCollideWithPlayer", (Type[])null, (Type[])null);
		}

		private static void Prefix(EnemyAI __instance, out EnemyAI __state)
		{
			__state = t_attacker;
			t_attacker = __instance;
		}

		private static Exception Finalizer(EnemyAI __state, Exception __exception)
		{
			t_attacker = __state;
			return __exception;
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "DamagePlayer")]
	internal static class DamagePatch
	{
		private static bool Prefix(PlayerControllerB __instance, int damageNumber, out int __state)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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)
			__state = __instance.health;
			if (damageNumber <= 0 || !((NetworkBehaviour)__instance).IsOwner || __instance.isPlayerDead || !(AttackScope.t_attacker is PufferAI))
			{
				return true;
			}
			__instance.KillPlayer(Vector3.zero, true, (CauseOfDeath)6, 0, default(Vector3), false);
			return false;
		}

		private static void Postfix(PlayerControllerB __instance, int __state)
		{
			//IL_0060: 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)
			if (((NetworkBehaviour)__instance).IsOwner && !__instance.isPlayerDead && __instance.health < __state && (AttackScope.t_attacker is HoarderBugAI || AttackScope.t_attacker is BaboonBirdAI) && (Object)(object)__instance.currentlyHeldObjectServer != (Object)null)
			{
				__instance.DiscardHeldObject(false, (NetworkObject)null, default(Vector3), true);
			}
		}
	}
	internal static class Content
	{
		internal static readonly Dictionary<Type, EnemyType> s_enemies = new Dictionary<Type, EnemyType>();

		internal static readonly Dictionary<Type, int> s_indoorWeights = new Dictionary<Type, int>();

		internal static Item s_sheet;

		internal static Item s_egg;

		internal static Item s_flashbang;

		internal static GameObject s_mine;

		internal static IndoorMapHazardType s_spikeHazard;

		internal static string Moon => ((Object)(object)RoundManager.Instance == (Object)null || (Object)(object)RoundManager.Instance.currentLevel == (Object)null) ? "" : Rules.MoonName(RoundManager.Instance.currentLevel.PlanetName);

		internal static void Load()
		{
			s_enemies.Clear();
			s_indoorWeights.Clear();
			EnemyType[] array = Resources.FindObjectsOfTypeAll<EnemyType>();
			foreach (EnemyType val in array)
			{
				if (!((Object)(object)val.enemyPrefab == (Object)null))
				{
					EnemyAI component = val.enemyPrefab.GetComponent<EnemyAI>();
					if ((Object)(object)component != (Object)null && !s_enemies.ContainsKey(((object)component).GetType()))
					{
						s_enemies.Add(((object)component).GetType(), val);
					}
				}
			}
			SelectableLevel[] levels = StartOfRound.Instance.levels;
			foreach (SelectableLevel val2 in levels)
			{
				foreach (SpawnableEnemyWithRarity enemy in val2.Enemies)
				{
					Type type = ((object)enemy.enemyType.enemyPrefab.GetComponent<EnemyAI>()).GetType();
					if (!s_indoorWeights.ContainsKey(type) || s_indoorWeights[type] < enemy.rarity)
					{
						s_indoorWeights[type] = enemy.rarity;
					}
				}
				IndoorMapHazard[] indoorMapHazards = val2.indoorMapHazards;
				foreach (IndoorMapHazard val3 in indoorMapHazards)
				{
					if ((Object)(object)val3.hazardType.prefabToSpawn.GetComponentInChildren<Landmine>(true) != (Object)null)
					{
						s_mine = val3.hazardType.prefabToSpawn;
					}
					if ((Object)(object)val3.hazardType.prefabToSpawn.GetComponentInChildren<SpikeRoofTrap>(true) != (Object)null)
					{
						s_spikeHazard = val3.hazardType;
					}
				}
				SpawnableMapObject[] spawnableMapObjects = val2.spawnableMapObjects;
				foreach (SpawnableMapObject val4 in spawnableMapObjects)
				{
					if ((Object)(object)val4.prefabToSpawn.GetComponentInChildren<Landmine>(true) != (Object)null)
					{
						s_mine = val4.prefabToSpawn;
					}
				}
			}
			List<Item> itemsList = StartOfRound.Instance.allItemsList.itemsList;
			s_sheet = itemsList.Single((Item x) => x.itemName.Equals("Metal sheet", StringComparison.OrdinalIgnoreCase) || x.itemName.Equals("Tattered metal sheet", StringComparison.OrdinalIgnoreCase));
			s_egg = itemsList.Single((Item x) => x.itemName.Equals("Easter egg", StringComparison.OrdinalIgnoreCase));
			s_flashbang = itemsList.Single((Item x) => x.itemName.Equals("Homemade flashbang", StringComparison.OrdinalIgnoreCase));
		}

		internal static EnemyType Enemy<T>() where T : EnemyAI
		{
			return s_enemies[typeof(T)];
		}

		internal static SpawnableEnemyWithRarity Entry<T>(int weight) where T : EnemyAI
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			return new SpawnableEnemyWithRarity(Enemy<T>(), weight);
		}
	}
	internal static class EnemyEvents
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__Receive;
		}

		internal const byte Bloom = 1;

		internal const byte Ghost = 2;

		private const string Message = "juanradical.moonoverhaul.enemy.v3";

		private static NetworkManager s_manager;

		internal static void Bind()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			Unbind();
			s_manager = NetworkManager.Singleton;
			CustomMessagingManager customMessagingManager = s_manager.CustomMessagingManager;
			object obj = <>O.<0>__Receive;
			if (obj == null)
			{
				HandleNamedMessageDelegate val = Receive;
				<>O.<0>__Receive = val;
				obj = (object)val;
			}
			customMessagingManager.RegisterNamedMessageHandler("juanradical.moonoverhaul.enemy.v3", (HandleNamedMessageDelegate)obj);
		}

		internal static void Unbind()
		{
			if ((Object)(object)s_manager != (Object)null && s_manager.CustomMessagingManager != null)
			{
				s_manager.CustomMessagingManager.UnregisterNamedMessageHandler("juanradical.moonoverhaul.enemy.v3");
			}
			s_manager = null;
		}

		internal unsafe static void Send(byte action, EnemyAI enemy, int player, Vector3 position, Vector3 rotation)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)s_manager == (Object)null || !s_manager.IsServer)
			{
				throw new InvalidOperationException("Enemy events must originate on the host.");
			}
			ulong networkObjectId = ((NetworkBehaviour)enemy).NetworkObjectId;
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(64, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteValueSafe<byte>(ref action, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref networkObjectId, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref player, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteValueSafe(ref position);
				((FastBufferWriter)(ref val)).WriteValueSafe(ref rotation);
				foreach (ulong connectedClientsId in s_manager.ConnectedClientsIds)
				{
					if (connectedClientsId != 0)
					{
						s_manager.CustomMessagingManager.SendNamedMessage("juanradical.moonoverhaul.enemy.v3", connectedClientsId, val, (NetworkDelivery)3);
					}
				}
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
			((MonoBehaviour)Plugin.Instance).StartCoroutine(Apply(action, networkObjectId, player, position, rotation));
		}

		private static void Receive(ulong sender, FastBufferReader reader)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			if (sender == 0L && !s_manager.IsServer)
			{
				byte action = default(byte);
				((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref action, default(ForPrimitives));
				ulong id = default(ulong);
				((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref id, default(ForPrimitives));
				int playerIndex = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref playerIndex, default(ForPrimitives));
				Vector3 position = default(Vector3);
				((FastBufferReader)(ref reader)).ReadValueSafe(ref position);
				Vector3 rotation = default(Vector3);
				((FastBufferReader)(ref reader)).ReadValueSafe(ref rotation);
				((MonoBehaviour)Plugin.Instance).StartCoroutine(Apply(action, id, playerIndex, position, rotation));
			}
		}

		private static IEnumerator Apply(byte action, ulong id, int playerIndex, Vector3 position, Vector3 rotation)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			int generation = Landings.Generation;
			float deadline = Time.realtimeSinceStartup + 8f;
			NetworkObject obj = null;
			while ((Object)(object)s_manager != (Object)null && generation == Landings.Generation && !s_manager.SpawnManager.SpawnedObjects.TryGetValue(id, out obj))
			{
				if (Time.realtimeSinceStartup >= deadline)
				{
					throw new InvalidOperationException($"Enemy event {action} could not resolve object {id}.");
				}
				yield return null;
			}
			if ((Object)(object)s_manager == (Object)null || generation != Landings.Generation)
			{
				yield break;
			}
			PlayerControllerB player = StartOfRound.Instance.allPlayerScripts[playerIndex];
			switch (action)
			{
			case 1:
			{
				CadaverBloomAI bloom = ((Component)obj).GetComponent<CadaverBloomAI>();
				if ((Object)(object)bloom == (Object)null)
				{
					throw new InvalidOperationException("Bloom event resolved a different enemy type.");
				}
				if (!((EnemyAI)bloom).isEnemyDead && !bloom.hasBurst)
				{
					bloom.BurstForth(player, false, position, rotation);
				}
				break;
			}
			default:
				throw new InvalidOperationException("Unknown enemy event.");
			case 2:
			{
				DressGirlAI ghost = ((Component)obj).GetComponent<DressGirlAI>();
				if ((Object)(object)ghost == (Object)null)
				{
					throw new InvalidOperationException("Ghost event resolved a different enemy type.");
				}
				ShowerGhosts.ChangeTarget(ghost, player);
				if ((Object)(object)GameNetworkManager.Instance.localPlayerController != (Object)(object)player)
				{
					break;
				}
				while ((Object)(object)ghost != (Object)null && !((NetworkBehaviour)ghost).IsOwner)
				{
					if (generation != Landings.Generation || (Object)(object)ghost.hauntingPlayer != (Object)(object)player || player.isPlayerDead || !player.isPlayerControlled)
					{
						yield break;
					}
					if (Time.realtimeSinceStartup >= deadline)
					{
						throw new InvalidOperationException("Ghost ownership transfer timed out.");
					}
					yield return null;
				}
				if (generation == Landings.Generation && (Object)(object)ghost != (Object)null && (Object)(object)ghost.hauntingPlayer == (Object)(object)player && !((EnemyAI)ghost).isEnemyDead && !player.isPlayerDead && player.isPlayerControlled)
				{
					ShowerGhosts.Attack(ghost, position);
				}
				break;
			}
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "Start")]
	internal static class BindEnemyEventsPatch
	{
		private static void Postfix()
		{
			EnemyEvents.Bind();
		}
	}
	[HarmonyPatch(typeof(EnemyAI), "Start")]
	internal static class EnemyLocationPatch
	{
		private static bool Applies(EnemyAI enemy)
		{
			return Content.Moon switch
			{
				"Experimentation" => enemy is FlowerSnakeEnemy, 
				"Assurance" => enemy is ButlerBeesEnemyAI, 
				"Vow" => enemy is SpringManAI, 
				"Offense" => enemy is CrawlerAI, 
				"Adamance" => enemy is HoarderBugAI, 
				"Dine" => enemy is ClaySurgeonAI, 
				"Embrion" => (enemy is PufferAI || enemy is JesterAI) ? true : false, 
				_ => false, 
			};
		}

		private static void Postfix(EnemyAI __instance)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (Levels.s_ready && Applies(__instance))
			{
				__instance.SetEnemyOutside(((Component)__instance).transform.position.y > -80f);
			}
		}
	}
	[HarmonyPatch(typeof(JesterAI), "Update")]
	internal static class JesterLocationPatch
	{
		private static bool SameArea(PlayerControllerB player, JesterAI jester)
		{
			return player.isInsideFactory != ((EnemyAI)jester).isOutside;
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			FieldInfo field = AccessTools.Field(typeof(PlayerControllerB), "isInsideFactory");
			foreach (CodeInstruction instruction in instructions)
			{
				if (!CodeInstructionExtensions.LoadsField(instruction, field, false))
				{
					yield return instruction;
					continue;
				}
				CodeInstruction load = new CodeInstruction(OpCodes.Ldarg_0, (object)null);
				load.labels.AddRange(instruction.labels);
				instruction.labels.Clear();
				load.blocks.AddRange(instruction.blocks);
				instruction.blocks.Clear();
				yield return load;
				instruction.opcode = OpCodes.Call;
				instruction.operand = AccessTools.Method(typeof(JesterLocationPatch), "SameArea", (Type[])null, (Type[])null);
				yield return instruction;
			}
		}
	}
	internal static class Landings
	{
		internal static readonly LandingEvents s_events = new LandingEvents();

		private static readonly List<NetworkObject> s_mines = new List<NetworkObject>();

		private static GameObject[] s_outside = Array.Empty<GameObject>();

		private static GameObject[] s_inside = Array.Empty<GameObject>();

		private static Random s_random;

		private static int s_generation;

		internal static int Generation => s_generation;

		internal static void Reset()
		{
			s_generation++;
			s_events.Reset();
			s_mines.Clear();
			s_outside = Array.Empty<GameObject>();
			s_inside = Array.Empty<GameObject>();
			Atmosphere.Clear();
			ShowerGhosts.Reset();
		}

		internal static void CacheNodes()
		{
			s_outside = GameObject.FindGameObjectsWithTag("OutsideAINode");
			s_inside = GameObject.FindGameObjectsWithTag("AINode");
			s_random = new Random(StartOfRound.Instance.randomMapSeed ^ 0x2D430);
		}

		internal static bool Position(bool outdoors, out Vector3 result)
		{
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			GameObject[] array = (outdoors ? s_outside : s_inside);
			NavMeshHit val3 = default(NavMeshHit);
			RaycastHit val5 = default(RaycastHit);
			for (int i = 0; i < 160 && array.Length != 0; i++)
			{
				GameObject val = array[s_random.Next(array.Length)];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Vector3 val2 = val.transform.position + new Vector3((float)s_random.NextDouble() * 12f - 6f, 0f, (float)s_random.NextDouble() * 12f - 6f);
				if (!NavMesh.SamplePosition(val2, ref val3, 6f, -1))
				{
					continue;
				}
				if (outdoors)
				{
					Vector3 val4 = StartOfRound.Instance.shipBounds.ClosestPoint(((NavMeshHit)(ref val3)).position) - ((NavMeshHit)(ref val3)).position;
					if (((Vector3)(ref val4)).sqrMagnitude < 64f)
					{
						continue;
					}
				}
				if (!Physics.Raycast(((NavMeshHit)(ref val3)).position + Vector3.up * 2f, Vector3.down, ref val5, 5f, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1))
				{
					continue;
				}
				result = ((RaycastHit)(ref val5)).point;
				return true;
			}
			result = default(Vector3);
			return false;
		}

		internal static EnemyAI Spawn<T>(bool outdoors) where T : EnemyAI
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			if (!Position(outdoors, out var result))
			{
				throw new InvalidOperationException("No valid " + (outdoors ? "outdoor" : "indoor") + " spawn point for " + typeof(T).Name);
			}
			NetworkObjectReference val = RoundManager.Instance.SpawnEnemyGameObject(result, (float)s_random.Next(360), -1, Content.Enemy<T>());
			NetworkObject val2 = default(NetworkObject);
			if (!((NetworkObjectReference)(ref val)).TryGet(ref val2, (NetworkManager)null))
			{
				throw new InvalidOperationException("Spawn failed for " + typeof(T).Name);
			}
			return ((Component)val2).GetComponent<EnemyAI>();
		}

		internal static IEnumerator Land()
		{
			int thisGeneration = s_generation;
			yield return null;
			if (thisGeneration != s_generation || !Levels.s_ready)
			{
				yield break;
			}
			CacheNodes();
			Atmosphere.Apply();
			if (!((NetworkBehaviour)RoundManager.Instance).IsServer || !s_events.Pending("landing"))
			{
				yield break;
			}
			s_events.Done("landing");
			string moon = Content.Moon;
			if (HasGuaranteedSapsucker(moon) && !RoundManager.Instance.SpawnedEnemies.Any((EnemyAI x) => x is GiantKiwiAI && !x.isEnemyDead))
			{
				Landings.Spawn<GiantKiwiAI>(outdoors: true);
				Plugin.Log.LogInfo((object)("Spawned guaranteed sapsucker on " + moon + "."));
			}
			if (moon == "Experimentation")
			{
				if ((Object)(object)Content.s_mine == (Object)null)
				{
					throw new InvalidOperationException("Couldn't find landmine prefab!!");
				}
				for (int i = 0; i < 40; i++)
				{
					if (!Position(outdoors: true, out var p))
					{
						throw new InvalidOperationException($"Only placed {i}/40 outdoor mines: no valid ground.");
					}
					GameObject obj = Object.Instantiate<GameObject>(Content.s_mine, p, Quaternion.Euler(0f, (float)s_random.Next(360), 0f));
					NetworkObject net = obj.GetComponentInChildren<NetworkObject>();
					if ((Object)(object)net == (Object)null)
					{
						throw new InvalidOperationException("Landmine prefab has no NetworkObject!!");
					}
					net.Spawn(true);
					s_mines.Add(net);
					if (i % 5 == 4)
					{
						yield return null;
						if (thisGeneration != s_generation)
						{
							yield break;
						}
					}
					p = default(Vector3);
				}
				Plugin.Log.LogInfo((object)"Spawned experimentation mines");
				ExtraSpikes();
			}
			if (moon == "Titan")
			{
				int wanted = s_random.Next(2, 6);
				for (int i2 = 0; i2 < wanted; i2++)
				{
					Landings.Spawn<RedLocustBees>(outdoors: true);
					yield return null;
					if (thisGeneration != s_generation)
					{
						yield break;
					}
				}
				Plugin.Log.LogInfo((object)$"Trying to spawn {wanted} bees on titan");
			}
			if (moon == "Embrion")
			{
				if (!RoundManager.Instance.SpawnedEnemies.Any((EnemyAI x) => x is DressGirlAI && !x.isEnemyDead))
				{
					Landings.Spawn<DressGirlAI>(outdoors: false);
				}
				s_events.Done("ghost");
			}
		}

		private static bool HasGuaranteedSapsucker(string moon)
		{
			switch (moon)
			{
			case "Titan":
			case "Artifice":
			case "Experimentation":
			case "Offense":
				return true;
			default:
				return false;
			}
		}

		private static void ExtraSpikes()
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			if ((Object)(object)Content.s_spikeHazard == (Object)null)
			{
				throw new InvalidOperationException("Couldnt find spike traps!!");
			}
			RoundManager instance = RoundManager.Instance;
			SelectableLevel currentLevel = instance.currentLevel;
			IndoorMapHazard[] indoorMapHazards = currentLevel.indoorMapHazards;
			SpawnableMapObject[] spawnableMapObjects = currentLevel.spawnableMapObjects;
			int increasedMapHazardSpawnRateIndex = instance.increasedMapHazardSpawnRateIndex;
			try
			{
				currentLevel.indoorMapHazards = (IndoorMapHazard[])(object)new IndoorMapHazard[1]
				{
					new IndoorMapHazard
					{
						hazardType = Content.s_spikeHazard,
						numberToSpawn = AnimationCurve.Constant(0f, 1f, 8f)
					}
				};
				currentLevel.spawnableMapObjects = Array.Empty<SpawnableMapObject>();
				instance.increasedMapHazardSpawnRateIndex = -1;
				instance.SpawnMapObjects();
			}
			finally
			{
				currentLevel.indoorMapHazards = indoorMapHazards;
				currentLevel.spawnableMapObjects = spawnableMapObjects;
				instance.increasedMapHazardSpawnRateIndex = increasedMapHazardSpawnRateIndex;
			}
			Plugin.Log.LogInfo((object)"Requested 8 indoor spike traps using vanilla placement.");
		}

		internal static void Clock()
		{
			if (Levels.s_ready && !(Content.Moon != "Embrion") && StartOfRound.Instance.shipHasLanded && !StartOfRound.Instance.shipIsLeaving && ((NetworkBehaviour)RoundManager.Instance).IsServer && s_events.Pending("jester") && Rules.IsTenPm(TimeOfDay.Instance.normalizedTimeOfDay, TimeOfDay.Instance.numberOfHours))
			{
				Landings.Spawn<JesterAI>(outdoors: true);
				s_events.Done("jester");
				Plugin.Log.LogInfo((object)"22:00: Jester has landed...");
			}
		}

		internal static void Cleanup()
		{
			if ((Object)(object)RoundManager.Instance != (Object)null && ((NetworkBehaviour)RoundManager.Instance).IsServer)
			{
				foreach (NetworkObject s_mine in s_mines)
				{
					if ((Object)(object)s_mine != (Object)null && s_mine.IsSpawned)
					{
						s_mine.Despawn(true);
					}
				}
			}
			Reset();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "OnShipLandedMiscEvents")]
	internal static class LandPatch
	{
		private static void Postfix()
		{
			((MonoBehaviour)Plugin.Instance).StartCoroutine(Landings.Land());
		}
	}
	[HarmonyPatch(typeof(RoundManager), "Update")]
	internal static class ClockPatch
	{
		private static void Postfix()
		{
			Landings.Clock();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "ShipHasLeft")]
	internal static class LeavePatch
	{
		private static void Prefix()
		{
			Landings.Cleanup();
		}
	}
	internal static class Levels
	{
		internal sealed class Baseline
		{
			internal List<SpawnableEnemyWithRarity> _inside;

			internal List<SpawnableEnemyWithRarity> _outside;

			internal List<SpawnableItemWithRarity> _scrap;

			internal int _minScrap;

			internal int _maxScrap;

			internal int _power;

			internal int _diversity;

			internal float _size;

			internal AnimationCurve _spawnCurve;

			internal AnimationCurve[] _traps;

			internal AnimationCurve[] _hazards;

			internal Baseline(SelectableLevel l)
			{
				_inside = Copy(l.Enemies);
				_outside = Copy(l.OutsideEnemies);
				_scrap = CopyScrap(l.spawnableScrap);
				_minScrap = l.minScrap;
				_maxScrap = l.maxScrap;
				_power = l.maxEnemyPowerCount;
				_diversity = l.maxInsideDiversityPowerCount;
				_size = l.factorySizeMultiplier;
				_spawnCurve = l.enemySpawnChanceThroughoutDay;
				_traps = l.spawnableMapObjects.Select((SpawnableMapObject x) => x.numberToSpawn).ToArray();
				_hazards = l.indoorMapHazards.Select((IndoorMapHazard x) => x.numberToSpawn).ToArray();
			}

			internal void Restore(SelectableLevel l)
			{
				l.Enemies = Copy(_inside);
				l.OutsideEnemies = Copy(_outside);
				l.spawnableScrap = CopyScrap(_scrap);
				l.minScrap = _minScrap;
				l.maxScrap = _maxScrap;
				l.maxEnemyPowerCount = _power;
				l.maxInsideDiversityPowerCount = _diversity;
				l.factorySizeMultiplier = _size;
				l.enemySpawnChanceThroughoutDay = _spawnCurve;
				for (int i = 0; i < _traps.Length; i++)
				{
					l.spawnableMapObjects[i].numberToSpawn = _traps[i];
				}
				for (int j = 0; j < _hazards.Length; j++)
				{
					l.indoorMapHazards[j].numberToSpawn = _hazards[j];
				}
			}
		}

		private static readonly Dictionary<SelectableLevel, Baseline> s_originals = new Dictionary<SelectableLevel, Baseline>();

		private static readonly Dictionary<EnemyType, (int max, bool falloff)> s_caps = new Dictionary<EnemyType, (int, bool)>();

		private static List<SpawnableEnemyWithRarity> s_originalWeeds;

		internal static float s_scrapValue = 1f;

		internal static bool s_ready;

		private static List<SpawnableEnemyWithRarity> Copy(List<SpawnableEnemyWithRarity> list)
		{
			return ((IEnumerable<SpawnableEnemyWithRarity>)list).Select((Func<SpawnableEnemyWithRarity, SpawnableEnemyWithRarity>)((SpawnableEnemyWithRarity x) => new SpawnableEnemyWithRarity(x.enemyType, x.rarity))).ToList();
		}

		private static List<SpawnableItemWithRarity> CopyScrap(List<SpawnableItemWithRarity> list)
		{
			return ((IEnumerable<SpawnableItemWithRarity>)list).Select((Func<SpawnableItemWithRarity, SpawnableItemWithRarity>)((SpawnableItemWithRarity x) => new SpawnableItemWithRarity(x.spawnableItem, x.rarity))).ToList();
		}

		private static AnimationCurve Scale(AnimationCurve original, float multiplier)
		{
			//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_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			Keyframe[] keys = original.keys;
			for (int i = 0; i < keys.Length; i++)
			{
				ref Keyframe reference = ref keys[i];
				((Keyframe)(ref reference)).value = ((Keyframe)(ref reference)).value * multiplier;
				if (!float.IsInfinity(((Keyframe)(ref keys[i])).inTangent))
				{
					ref Keyframe reference2 = ref keys[i];
					((Keyframe)(ref reference2)).inTangent = ((Keyframe)(ref reference2)).inTangent * multiplier;
				}
				if (!float.IsInfinity(((Keyframe)(ref keys[i])).outTangent))
				{
					ref Keyframe reference3 = ref keys[i];
					((Keyframe)(ref reference3)).outTangent = ((Keyframe)(ref reference3)).outTangent * multiplier;
				}
			}
			return new AnimationCurve(keys)
			{
				preWrapMode = original.preWrapMode,
				postWrapMode = original.postWrapMode
			};
		}

		private static void Multiply<T>(List<SpawnableEnemyWithRarity> pool, float amount) where T : EnemyAI
		{
			SpawnableEnemyWithRarity val = pool.Find((SpawnableEnemyWithRarity x) => (Object)(object)x.enemyType == (Object)(object)Content.Enemy<T>());
			if (val != null)
			{
				val.rarity = Mathf.RoundToInt((float)val.rarity * amount);
			}
		}

		private static void Common<T>(List<SpawnableEnemyWithRarity> pool) where T : EnemyAI
		{
			pool.RemoveAll((SpawnableEnemyWithRarity x) => (Object)(object)x.enemyType == (Object)(object)Content.Enemy<T>());
			pool.Add(Content.Entry<T>(Math.Max(1, Rules.ShareWeight(pool.Select((SpawnableEnemyWithRarity x) => x.rarity).ToArray(), 0.5))));
		}

		private static void Unlimited<T>() where T : EnemyAI
		{
			EnemyType val = Content.Enemy<T>();
			if (!s_caps.ContainsKey(val))
			{
				s_caps.Add(val, (val.MaxCount, val.useNumberSpawnedFalloff));
			}
			val.MaxCount = int.MaxValue;
			val.useNumberSpawnedFalloff = false;
		}

		private static void MultiplyCap<T>(int multiplier) where T : EnemyAI
		{
			EnemyType val = Content.Enemy<T>();
			if (!s_caps.ContainsKey(val))
			{
				s_caps.Add(val, (val.MaxCount, val.useNumberSpawnedFalloff));
			}
			val.MaxCount = checked(s_caps[val].max * multiplier);
		}

		private static void Add<T>(List<SpawnableEnemyWithRarity> pool, int weight) where T : EnemyAI
		{
			if (!pool.Any((SpawnableEnemyWithRarity x) => (Object)(object)x.enemyType == (Object)(object)Content.Enemy<T>()))
			{
				pool.Add(Content.Entry<T>(weight));
			}
		}

		internal static void Apply(SelectableLevel l)
		{
			//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ac: Expected O, but got Unknown
			//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bf: Expected O, but got Unknown
			//IL_0695: Unknown result type (might be due to invalid IL or missing references)
			//IL_069f: Expected O, but got Unknown
			//IL_054e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0558: Expected O, but got Unknown
			s_ready = false;
			if (s_originals.Count == 0)
			{
				Content.Load();
			}
			if (s_originalWeeds == null)
			{
				s_originalWeeds = Copy(RoundManager.Instance.WeedEnemies);
			}
			RoundManager.Instance.WeedEnemies = Copy(s_originalWeeds);
			if (!s_originals.TryGetValue(l, out var value))
			{
				s_originals.Add(l, value = new Baseline(l));
			}
			value.Restore(l);
			foreach (KeyValuePair<EnemyType, (int, bool)> s_cap in s_caps)
			{
				s_cap.Key.MaxCount = s_cap.Value.Item1;
				s_cap.Key.useNumberSpawnedFalloff = s_cap.Value.Item2;
			}
			Unlimited<PufferAI>();
			Unlimited<ClaySurgeonAI>();
			Unlimited<CaveDwellerAI>();
			Unlimited<PumaAI>();
			float num = 1f;
			float num2 = 1f;
			float num3 = 1f;
			s_scrapValue = 1f;
			switch (Rules.MoonName(l.PlanetName))
			{
			case "Experimentation":
			{
				num = 1.5f;
				num2 = 4f;
				MultiplyCap<FlowerSnakeEnemy>(5);
				SpawnableItemWithRarity val = l.spawnableScrap.Find((SpawnableItemWithRarity x) => (Object)(object)x.spawnableItem == (Object)(object)Content.s_sheet);
				if (val != null)
				{
					val.rarity *= 5;
				}
				Common<FlowerSnakeEnemy>(l.Enemies);
				break;
			}
			case "Assurance":
				num = 1.5f;
				num2 = 1.5f;
				l.spawnableScrap = new List<SpawnableItemWithRarity>
				{
					new SpawnableItemWithRarity(Content.s_egg, 90),
					new SpawnableItemWithRarity(Content.s_flashbang, 10)
				};
				Common<HoarderBugAI>(l.Enemies);
				Add<ButlerBeesEnemyAI>(l.OutsideEnemies, 50);
				break;
			case "Vow":
				l.OutsideEnemies = new List<SpawnableEnemyWithRarity>
				{
					Content.Entry<PumaAI>(50),
					Content.Entry<SpringManAI>(20)
				};
				Multiply<CaveDwellerAI>(l.Enemies, 3f);
				break;
			case "Offense":
			{
				num3 = 5f;
				s_scrapValue = 1.8f;
				Type[] allowed = new Type[8]
				{
					typeof(SandSpiderAI),
					typeof(BlobAI),
					typeof(CentipedeAI),
					typeof(SpringManAI),
					typeof(StingrayAI),
					typeof(CaveDwellerAI),
					typeof(FlowermanAI),
					typeof(NutcrackerEnemyAI)
				};
				l.Enemies.RemoveAll((SpawnableEnemyWithRarity x) => !allowed.Contains(((object)x.enemyType.enemyPrefab.GetComponent<EnemyAI>()).GetType()));
				Type[] array = allowed;
				foreach (Type t in array)
				{
					if (!l.Enemies.Any((SpawnableEnemyWithRarity x) => (Object)(object)x.enemyType == (Object)(object)Content.s_enemies[t]))
					{
						l.Enemies.Add(new SpawnableEnemyWithRarity(Content.s_enemies[t], Content.s_indoorWeights[t]));
					}
				}
				l.OutsideEnemies = new List<SpawnableEnemyWithRarity> { Content.Entry<CrawlerAI>(100) };
				break;
			}
			case "March":
				num = 0.8f;
				s_scrapValue = 3f;
				l.factorySizeMultiplier = 2.1f;
				break;
			case "Adamance":
				s_scrapValue = 2f;
				Unlimited<CadaverGrowthAI>();
				l.Enemies = new List<SpawnableEnemyWithRarity>
				{
					Content.Entry<CadaverGrowthAI>(50),
					Content.Entry<CadaverBloomAI>(10),
					Content.Entry<ButlerEnemyAI>(15),
					Content.Entry<JesterAI>(15),
					Content.Entry<DressGirlAI>(10),
					Content.Entry<MaskedPlayerEnemy>(5)
				};
				l.OutsideEnemies = new List<SpawnableEnemyWithRarity> { Content.Entry<HoarderBugAI>(100) };
				break;
			case "Rend":
				num2 = 1.8f;
				s_scrapValue = 1.2f;
				Multiply<NutcrackerEnemyAI>(l.Enemies, 2.5f);
				break;
			case "Dine":
				num = 1.1f;
				s_scrapValue = 0.9f;
				l.spawnableScrap.Add(new SpawnableItemWithRarity(Content.s_sheet, 750));
				l.OutsideEnemies = new List<SpawnableEnemyWithRarity> { Content.Entry<ClaySurgeonAI>(100) };
				break;
			case "Titan":
				num2 = 1.4f;
				num3 = 1.5f;
				break;
			case "Artifice":
				num2 = 2f;
				num = 1.5f;
				num3 = 1.5f;
				break;
			case "Embrion":
				num = 2f;
				num2 = 1.5f;
				num3 = 1.6f;
				l.OutsideEnemies = new List<SpawnableEnemyWithRarity> { Content.Entry<PufferAI>(100) };
				break;
			}
			string text = Rules.MoonName(l.PlanetName);
			switch (text)
			{
			default:
				if (!(text == "Embrion"))
				{
					break;
				}
				goto case "Vow";
			case "Vow":
			case "Offense":
			case "Adamance":
			case "Dine":
				RoundManager.Instance.WeedEnemies.RemoveAll((SpawnableEnemyWithRarity x) => !l.OutsideEnemies.Any((SpawnableEnemyWithRarity e) => (Object)(object)e.enemyType == (Object)(object)x.enemyType));
				break;
			}
			l.minScrap = Mathf.RoundToInt((float)value._minScrap * num);
			l.maxScrap = Mathf.RoundToInt((float)value._maxScrap * num);
			l.maxEnemyPowerCount = Mathf.CeilToInt((float)value._power * num2);
			l.maxInsideDiversityPowerCount = Mathf.CeilToInt((float)value._diversity * num2);
			l.enemySpawnChanceThroughoutDay = Scale(value._spawnCurve, num2);
			for (int num5 = 0; num5 < l.spawnableMapObjects.Length; num5++)
			{
				GameObject prefabToSpawn = l.spawnableMapObjects[num5].prefabToSpawn;
				if ((Object)(object)prefabToSpawn.GetComponentInChildren<Landmine>(true) != (Object)null || (Object)(object)prefabToSpawn.GetComponentInChildren<Turret>(true) != (Object)null || (Object)(object)prefabToSpawn.GetComponentInChildren<SpikeRoofTrap>(true) != (Object)null)
				{
					l.spawnableMapObjects[num5].numberToSpawn = Scale(value._traps[num5], num3);
				}
			}
			for (int num6 = 0; num6 < l.indoorMapHazards.Length; num6++)
			{
				GameObject prefabToSpawn2 = l.indoorMapHazards[num6].hazardType.prefabToSpawn;
				if ((Object)(object)prefabToSpawn2.GetComponentInChildren<Landmine>(true) != (Object)null || (Object)(object)prefabToSpawn2.GetComponentInChildren<Turret>(true) != (Object)null || (Object)(object)prefabToSpawn2.GetComponentInChildren<SpikeRoofTrap>(true) != (Object)null)
				{
					l.indoorMapHazards[num6].numberToSpawn = Scale(value._hazards[num6], num3);
				}
			}
			s_ready = true;
			Plugin.Log.LogInfo((object)$"APPLIED MODIFIERS!! 1-{l.PlanetName}|2-{num}|3-{s_scrapValue}|4-{num2}|5-{num3}");
		}

		internal static void RestoreAll()
		{
			foreach (KeyValuePair<SelectableLevel, Baseline> s_original in s_originals)
			{
				if ((Object)(object)s_original.Key != (Object)null)
				{
					s_original.Value.Restore(s_original.Key);
				}
			}
			foreach (KeyValuePair<EnemyType, (int, bool)> s_cap in s_caps)
			{
				if ((Object)(object)s_cap.Key != (Object)null)
				{
					s_cap.Key.MaxCount = s_cap.Value.Item1;
					s_cap.Key.useNumberSpawnedFalloff = s_cap.Value.Item2;
				}
			}
			if (s_originalWeeds != null && (Object)(object)RoundManager.Instance != (Object)null)
			{
				RoundManager.Instance.WeedEnemies = Copy(s_originalWeeds);
			}
			s_originalWeeds = null;
			s_originals.Clear();
			s_caps.Clear();
			s_ready = false;
		}
	}
	[HarmonyPatch(typeof(RoundManager), "SpawnRandomWeedEnemy")]
	internal static class EmptyWeedPoolPatch
	{
		private static bool Prefix(RoundManager __instance, ref bool __result)
		{
			if (!Levels.s_ready || __instance.WeedEnemies.Count > 0)
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(RoundManager), "GenerateNewFloor")]
	internal static class GeneratePatch
	{
		[HarmonyPrefix]
		[HarmonyPriority(0)]
		private static void Prefix(RoundManager __instance)
		{
			Levels.Apply(__instance.currentLevel);
			Landings.Reset();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "OnDestroy")]
	internal static class RoundEndPatch
	{
		private static void Prefix()
		{
			EnemyEvents.Unbind();
			Levels.RestoreAll();
			Landings.Reset();
		}
	}
	[BepInPlugin("juanradical.moonoverhaul", "RadsMoons", "1.0.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		internal const string PluginGuid = "juanradical.moonoverhaul";

		internal const string PluginName = "RadsMoons";

		internal const string PluginVersion = "1.0.1";

		private Harmony _harmony;

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			_harmony = new Harmony("juanradical.moonoverhaul");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"RadsMoons 1.0.1 loaded. Install on every player.");
		}

		private void OnDestroy()
		{
			EnemyEvents.Unbind();
			Levels.RestoreAll();
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}
	}
	internal static class Rules
	{
		internal static int ShareWeight(int[] otherWeights, double share)
		{
			if (share <= 0.0 || share >= 1.0)
			{
				throw new ArgumentOutOfRangeException("share");
			}
			return checked((int)Math.Round((double)((IEnumerable<int>)otherWeights).Sum((Func<int, long>)((int x) => x)) * share / (1.0 - share)));
		}

		internal static string MoonName(string value)
		{
			value = value.Trim();
			int num = value.IndexOf(' ');
			int result;
			return (num > 0 && int.TryParse(value.Substring(0, num), out result)) ? value.Substring(num + 1).Trim() : value;
		}

		internal static bool IsTenPm(float normalizedTime, float numberOfHours = 18f)
		{
			return normalizedTime >= 16f / numberOfHours;
		}

		internal static bool EggExplodes(int roll)
		{
			return roll < 25;
		}

		internal static int OtherPlayer(int[] livingPlayers, int current, Random random)
		{
			int[] array = livingPlayers.Where((int id) => id != current).ToArray();
			return (array.Length == 0) ? (-1) : array[random.Next(array.Length)];
		}
	}
	internal sealed class ShowerVisit
	{
		private readonly HashSet<int> _used = new HashSet<int>();

		internal bool Available(int player)
		{
			return !_used.Contains(player);
		}

		internal void Used(int player)
		{
			_used.Add(player);
		}

		internal void Leave(int player)
		{
			_used.Remove(player);
		}
	}
	internal sealed class LandingEvents
	{
		private readonly HashSet<string> _completed = new HashSet<string>();

		internal bool Pending(string name)
		{
			return !_completed.Contains(name);
		}

		internal void Done(string name)
		{
			_completed.Add(name);
		}

		internal void Reset()
		{
			_completed.Clear();
		}
	}
	[HarmonyPatch(typeof(RoundManager), "SpawnScrapInLevel")]
	internal static class ScrapPatch
	{
		private static Random s_random;

		private static List<SpawnableItemWithRarity> s_pool;

		private static int s_totalWeight;

		private static void Prefix(RoundManager __instance)
		{
			s_pool = __instance.currentLevel.spawnableScrap;
			s_totalWeight = s_pool.Sum((SpawnableItemWithRarity x) => x.rarity);
			s_random = new Random(StartOfRound.Instance.randomMapSeed ^ 0x193E);
		}

		private static Exception Finalizer(Exception __exception)
		{
			s_pool = null;
			return __exception;
		}

		private static void AddScrap(List<Item> selected, Item original)
		{
			if (Content.Moon != "Assurance" && Content.Moon != "Dine")
			{
				selected.Add(original);
				return;
			}
			int num = s_random.Next(s_totalWeight);
			foreach (SpawnableItemWithRarity item in s_pool)
			{
				num -= item.rarity;
				if (num >= 0)
				{
					continue;
				}
				selected.Add(item.spawnableItem);
				return;
			}
			throw new InvalidOperationException("Scrap spawn weights are invalid");
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo original = AccessTools.Method(typeof(List<Item>), "Add", (Type[])null, (Type[])null);
			MethodInfo replacement = AccessTools.Method(typeof(ScrapPatch), "AddScrap", (Type[])null, (Type[])null);
			int changed = 0;
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, original))
				{
					instruction.opcode = OpCodes.Call;
					instruction.operand = replacement;
					changed++;
				}
				yield return instruction;
			}
			if (changed == 0)
			{
				throw new InvalidOperationException("Unsupported game version: scrap list insertion was not found.");
			}
		}
	}
	[HarmonyPatch(typeof(RoundManager), "waitForScrapToSpawnToSync")]
	internal static class ScrapValuePatch
	{
		private static void Prefix(NetworkObjectReference[] spawnedScrap, int[] scrapValues)
		{
			if (!((NetworkBehaviour)RoundManager.Instance).IsServer || Levels.s_scrapValue == 1f)
			{
				return;
			}
			NetworkObject val = default(NetworkObject);
			for (int i = 0; i < scrapValues.Length; i++)
			{
				scrapValues[i] = Mathf.RoundToInt((float)scrapValues[i] * Levels.s_scrapValue);
				if (((NetworkObjectReference)(ref spawnedScrap[i])).TryGet(ref val, (NetworkManager)null))
				{
					((Component)val).GetComponent<GrabbableObject>().SetScrapValue(scrapValues[i]);
				}
			}
		}
	}
	[HarmonyPatch(typeof(StunGrenadeItem), "SetExplodeOnThrowServerRpc")]
	internal static class EggPatch
	{
		internal static bool IsEgg(StunGrenadeItem item)
		{
			return ((GrabbableObject)item).itemProperties.itemName.Equals("Easter egg", StringComparison.OrdinalIgnoreCase);
		}

		private static void Prefix(StunGrenadeItem __instance)
		{
			if (IsEgg(__instance))
			{
				__instance.chanceToExplode = 25f;
			}
		}

		private static int Roll(Random random, int min, int max, StunGrenadeItem item)
		{
			int num = random.Next(min, max);
			return (!IsEgg(item) || min != 0 || max != 100) ? num : ((!Rules.EggExplodes(num)) ? 100 : 0);
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo next = AccessTools.Method(typeof(Random), "Next", new Type[2]
			{
				typeof(int),
				typeof(int)
			}, (Type[])null);
			int changed = 0;
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, next))
				{
					CodeInstruction load = new CodeInstruction(OpCodes.Ldarg_0, (object)null);
					load.labels.AddRange(instruction.labels);
					instruction.labels.Clear();
					load.blocks.AddRange(instruction.blocks);
					instruction.blocks.Clear();
					yield return load;
					instruction.opcode = OpCodes.Call;
					instruction.operand = AccessTools.Method(typeof(EggPatch), "Roll", (Type[])null, (Type[])null);
					changed++;
				}
				yield return instruction;
			}
			if (changed == 0)
			{
				throw new InvalidOperationException("Couldn't change egg explode chance!!");
			}
		}
	}
	[HarmonyPatch(typeof(ShipBuildModeManager), "Update")]
	internal static class ShipPlacementPatch
	{
		private static void Prefix(ShipBuildModeManager __instance)
		{
			__instance.ghostObjectRed = __instance.ghostObjectGreen;
		}

		private static void Postfix(ref bool ___CanConfirmPosition)
		{
			___CanConfirmPosition = true;
		}
	}
	[HarmonyPatch(typeof(ShipBuildModeManager), "ConfirmBuildMode_performed")]
	internal static class ShipPlacementConfirmPatch
	{
		private static void Prefix(ref bool ___CanConfirmPosition)
		{
			___CanConfirmPosition = true;
		}
	}
	[HarmonyPatch(typeof(ShotgunItem), "Update")]
	internal static class ShotgunMisfirePatch
	{
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			List<CodeInstruction> list = instructions.ToList();
			FieldInfo fieldInfo = AccessTools.Field(typeof(ShotgunItem), "misfireTimer");
			MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(Time), "deltaTime");
			int num = 0;
			for (int i = 0; i < list.Count - 3; i++)
			{
				if (CodeInstructionExtensions.LoadsField(list[i], fieldInfo, false) && CodeInstructionExtensions.Calls(list[i + 1], methodInfo) && !(list[i + 2].opcode != OpCodes.Sub) && CodeInstructionExtensions.StoresField(list[i + 3], fieldInfo))
				{
					list.InsertRange(i + 2, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[2]
					{
						new CodeInstruction(OpCodes.Ldc_R4, (object)5f),
						new CodeInstruction(OpCodes.Mul, (object)null)
					});
					num++;
					i += 5;
				}
			}
			if (num != 1)
			{
				throw new InvalidOperationException($"Expected one shotgun misfire countdown, found {num}.");
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "LoadUnlockables")]
	internal static class ShowerUnlockPatch
	{
		internal static void Postfix(StartOfRound __instance)
		{
			if (((NetworkBehaviour)__instance).IsServer)
			{
				UnlockableItem val = __instance.unlockablesList.unlockables.Single((UnlockableItem x) => x.unlockableName.Equals("Shower", StringComparison.OrdinalIgnoreCase));
				if (!val.hasBeenUnlockedByPlayer && !val.alreadyUnlocked)
				{
					val.hasBeenUnlockedByPlayer = true;
					val.inStorage = true;
					Plugin.Log.LogInfo((object)"Shower unlocked automatically");
				}
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "ResetShip")]
	internal static class ShowerResetPatch
	{
		private static void Postfix(StartOfRound __instance)
		{
			ShowerUnlockPatch.Postfix(__instance);
		}
	}
	[HarmonyPatch(typeof(ShowerTrigger), "Update")]
	internal static class ShowerCurePatch
	{
		private static void Postfix(ShowerTrigger __instance, bool ___showerOn)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			ShowerGhosts.Update(__instance, ___showerOn);
			if (!___showerOn || (Object)(object)RoundManager.Instance == (Object)null)
			{
				return;
			}
			PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController;
			if ((Object)(object)localPlayerController == (Object)null || localPlayerController.isPlayerDead)
			{
				return;
			}
			Bounds bounds = __instance.showerCollider.bounds;
			if (!((Bounds)(ref bounds)).Contains(((Component)localPlayerController.gameplayCamera).transform.position))
			{
				return;
			}
			int num = (int)localPlayerController.playerClientId;
			foreach (EnemyAI spawnedEnemy in RoundManager.Instance.SpawnedEnemies)
			{
				CadaverGrowthAI val = (CadaverGrowthAI)(object)((spawnedEnemy is CadaverGrowthAI) ? spawnedEnemy : null);
				if (val != null && !((EnemyAI)val).isEnemyDead && val.playerInfections != null && num < val.playerInfections.Length)
				{
					PlayerInfection val2 = val.playerInfections[num];
					if (val2 != null && (val2.infected || val2.infectionMeter > 0f || val2.burstMeter > 0f))
					{
						val.CurePlayer(num);
						val.CurePlayerRpc(num);
					}
				}
			}
		}
	}
	internal static class ShowerGhosts
	{
		private static readonly Dictionary<ShowerTrigger, ShowerVisit> s_visits = new Dictionary<ShowerTrigger, ShowerVisit>();

		private static readonly MethodInfo s_stop = AccessTools.Method(typeof(DressGirlAI), "StopChasing", (Type[])null, (Type[])null);

		private static readonly MethodInfo s_stare = AccessTools.Method(typeof(DressGirlAI), "SetHauntStarePosition", (Type[])null, (Type[])null);

		private static readonly MethodInfo s_chase = AccessTools.Method(typeof(DressGirlAI), "BeginChasing", (Type[])null, (Type[])null);

		private static readonly FieldInfo s_disappear = AccessTools.Field(typeof(DressGirlAI), "disappearOnDelayCoroutine");

		private static readonly FieldInfo s_switching = AccessTools.Field(typeof(DressGirlAI), "switchHauntedPlayerCoroutine");

		private static Random s_random;

		internal static void Reset()
		{
			s_visits.Clear();
			s_random = null;
		}

		internal static void Update(ShowerTrigger shower, bool running)
		{
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			if (!Levels.s_ready || (Object)(object)RoundManager.Instance == (Object)null || !((NetworkBehaviour)RoundManager.Instance).IsServer || !StartOfRound.Instance.shipHasLanded)
			{
				return;
			}
			if (!s_visits.TryGetValue(shower, out var value))
			{
				s_visits.Add(shower, value = new ShowerVisit());
			}
			if (s_random == null)
			{
				s_random = new Random(StartOfRound.Instance.randomMapSeed ^ 0x2C17);
			}
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			PlayerControllerB[] array = allPlayerScripts;
			NavMeshHit val6 = default(NavMeshHit);
			foreach (PlayerControllerB val in array)
			{
				int num = (int)val.playerClientId;
				if (running && val.isPlayerControlled && !val.isPlayerDead)
				{
					Bounds bounds = shower.showerCollider.bounds;
					if (((Bounds)(ref bounds)).Contains(((Component)val.gameplayCamera).transform.position))
					{
						if (!value.Available(num))
						{
							continue;
						}
						foreach (EnemyAI spawnedEnemy in RoundManager.Instance.SpawnedEnemies)
						{
							DressGirlAI val2 = (DressGirlAI)(object)((spawnedEnemy is DressGirlAI) ? spawnedEnemy : null);
							if (val2 == null || ((EnemyAI)val2).isEnemyDead || (Object)(object)val2.hauntingPlayer != (Object)(object)val)
							{
								continue;
							}
							int num2 = Rules.OtherPlayer((from p in allPlayerScripts
								where p.isPlayerControlled && !p.isPlayerDead
								select (int)p.playerClientId).ToArray(), num, s_random);
							if (num2 < 0)
							{
								continue;
							}
							PlayerControllerB val3 = allPlayerScripts[num2];
							GameObject[] array2 = (val3.isInsideFactory ? GameObject.FindGameObjectsWithTag("AINode") : GameObject.FindGameObjectsWithTag("OutsideAINode"));
							float num3 = float.PositiveInfinity;
							Vector3 position = default(Vector3);
							GameObject[] array3 = array2;
							foreach (GameObject val4 in array3)
							{
								Vector3 val5 = val4.transform.position - ((Component)val3).transform.position;
								float sqrMagnitude = ((Vector3)(ref val5)).sqrMagnitude;
								if (!(sqrMagnitude < 36f) && !(sqrMagnitude >= num3) && !(sqrMagnitude > 1600f) && NavMesh.SamplePosition(val4.transform.position, ref val6, 2f, -1))
								{
									num3 = sqrMagnitude;
									position = ((NavMeshHit)(ref val6)).position;
								}
							}
							if (float.IsPositiveInfinity(num3))
							{
								throw new InvalidOperationException("No valid nearby ghost spawn point for shower transfer.");
							}
							ChangeTarget(val2, val3);
							EnemyEvents.Send(2, (EnemyAI)(object)val2, num2, position, Vector3.zero);
							((EnemyAI)val2).ChangeOwnershipOfEnemy(val3.actualClientId);
							value.Used(num);
							Plugin.Log.LogInfo((object)$"Transferred ghost girl from player {num} to {num2}");
						}
						continue;
					}
				}
				value.Leave(num);
			}
		}

		internal static void ChangeTarget(DressGirlAI ghost, PlayerControllerB player)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			Coroutine val = (Coroutine)s_disappear.GetValue(ghost);
			if (val != null)
			{
				((MonoBehaviour)ghost).StopCoroutine(val);
				s_disappear.SetValue(ghost, null);
			}
			val = (Coroutine)s_switching.GetValue(ghost);
			if (val != null)
			{
				((MonoBehaviour)ghost).StopCoroutine(val);
				s_switching.SetValue(ghost, null);
			}
			s_stop.Invoke(ghost, null);
			ghost.heartbeatMusic.volume = 0f;
			((EnemyAI)ghost).creatureSFX.Stop();
			ghost.hauntingPlayer = player;
			ghost.hauntingLocalPlayer = (Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)(object)player;
			ghost.staringInHaunt = false;
			ghost.disappearingFromStare = false;
			AccessTools.Field(typeof(DressGirlAI), "switchedHauntingPlayer").SetValue(ghost, false);
		}

		internal static void Attack(DressGirlAI ghost, Vector3 position)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			((EnemyAI)ghost).SetEnemyOutside(!ghost.hauntingPlayer.isInsideFactory);
			s_stare.Invoke(ghost, new object[2] { position, 0f });
			s_chase.Invoke(ghost, null);
		}
	}
	[HarmonyPatch(typeof(TimeOfDay), "DecideRandomDayEvents")]
	internal static class MeteorChancePatch
	{
		private static int Roll(Random random, int min, int max)
		{
			int num = random.Next(min, max);
			return (min == 0 && max == 1000) ? (num / 10) : num;
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo next = AccessTools.Method(typeof(Random), "Next", new Type[2]
			{
				typeof(int),
				typeof(int)
			}, (Type[])null);
			MethodInfo replacement = AccessTools.Method(typeof(MeteorChancePatch), "Roll", (Type[])null, (Type[])null);
			int changed = 0;
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, next))
				{
					instruction.opcode = OpCodes.Call;
					instruction.operand = replacement;
					changed++;
				}
				yield return instruction;
			}
			if (changed == 0)
			{
				throw new InvalidOperationException("Meteor event random roll was not found.");
			}
		}
	}
}