Decompiled source of Apollo11 v1.0.4

BepInEx/plugins/RFGames-Apollo11/RFGames.Apollo11Mod.dll

Decompiled 19 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using Apollo11Mod.Enemies;
using Apollo11Mod.Items;
using Apollo11Mod.Moon;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Dissonance;
using Dissonance.Audio.Capture;
using GameNetcodeStuff;
using HarmonyLib;
using LethalLevelLoader;
using LethalLib.Modules;
using Microsoft.CodeAnalysis;
using NAudio.Wave;
using RFGames.Apollo11Mod.NetcodePatcher;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Audio;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("RFGames.Apollo11Mod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.4.0")]
[assembly: AssemblyInformationalVersion("1.0.4")]
[assembly: AssemblyProduct("Apollo11Mod")]
[assembly: AssemblyTitle("RFGames.Apollo11Mod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.4.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
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 Apollo11Mod
{
	internal static class DeanieRegistration
	{
		internal static EnemyType DeanieType;

		internal static int Rarity = 30;

		internal static int TestRarity = 1000;

		internal static string TestMoons = "";

		internal static void Register(AssetBundle bundle, ConfigFile cfg)
		{
			//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
			EnemyType val = bundle.LoadAsset<EnemyType>("DeanieEnemy");
			TerminalNode val2 = bundle.LoadAsset<TerminalNode>("DeanieTN");
			TerminalKeyword val3 = bundle.LoadAsset<TerminalKeyword>("DeanieTK");
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"DeanieEnemy not in bundle (build it with Apollo11BuildDeanie) - Deanie disabled.");
				return;
			}
			NetworkPrefabs.RegisterNetworkPrefab(val.enemyPrefab);
			Rarity = cfg.Bind<int>("Deanie", "Rarity", 30, "Spawn weight inside the Lunar Base on 11 Apollo.").Value;
			val.MaxCount = cfg.Bind<int>("Deanie", "MaxCount", 1, "Max Deanies alive at once.").Value;
			bool value = cfg.Bind<bool>("Deanie", "TestForceSpawn", false, "TESTING: huge spawn weight + spawn from the start of the day on TestMoons.").Value;
			TestRarity = cfg.Bind<int>("Deanie", "TestRarity", 1000, "Weight used when TestForceSpawn is true.").Value;
			TestMoons = (value ? cfg.Bind<string>("Deanie", "TestMoons", "Apollo", "Planet-name fragments (comma separated) or All.").Value : "");
			if (value)
			{
				val.probabilityCurve = AnimationCurve.Constant(0f, 1f, 1f);
			}
			DeanieSettings.FollowDistance = cfg.Bind<float>("Deanie", "FollowDistance", DeanieSettings.FollowDistance, "Cute form keeps about this far (m) from its player.").Value;
			DeanieSettings.AffectionPerPet = cfg.Bind<float>("Deanie", "AffectionPerPet", DeanieSettings.AffectionPerPet, "Affection added per completed pet (hold E ~1 s).").Value;
			DeanieSettings.AffectionThresholdMin = cfg.Bind<float>("Deanie", "ThresholdMin", DeanieSettings.AffectionThresholdMin, "Transform threshold is rolled per Deanie between ThresholdMin and ThresholdMax.").Value;
			DeanieSettings.AffectionThresholdMax = cfg.Bind<float>("Deanie", "ThresholdMax", DeanieSettings.AffectionThresholdMax, "See ThresholdMin.").Value;
			DeanieSettings.AffectionDecayPerSecond = cfg.Bind<float>("Deanie", "AffectionDecayPerSecond", DeanieSettings.AffectionDecayPerSecond, "How fast affection drains.").Value;
			DeanieSettings.AffectionOnHit = cfg.Bind<float>("Deanie", "AffectionOnHit", DeanieSettings.AffectionOnHit, "Affection added when the cute form is hit.").Value;
			DeanieSettings.HuntSpeed = cfg.Bind<float>("Deanie", "HuntSpeed", DeanieSettings.HuntSpeed, "Monster chase speed.").Value;
			DeanieSettings.CarrySpeed = cfg.Bind<float>("Deanie", "CarrySpeed", DeanieSettings.CarrySpeed, "Monster speed while carrying a player.").Value;
			DeanieSettings.MonsterHP = cfg.Bind<int>("Deanie", "MonsterHP", DeanieSettings.MonsterHP, "Monster health (shovel hit = 1).").Value;
			DeanieSettings.MonsterKillable = cfg.Bind<bool>("Deanie", "MonsterKillable", DeanieSettings.MonsterKillable, "Whether the monster form can be killed.").Value;
			DeanieSettings.HitsToDrop = cfg.Bind<int>("Deanie", "HitsToDrop", DeanieSettings.HitsToDrop, "Damage it takes while holding someone before it drops them and is stunned.").Value;
			DeanieSettings.StunAfterDrop = cfg.Bind<float>("Deanie", "StunAfterDrop", DeanieSettings.StunAfterDrop, "Stun seconds after dropping a victim.").Value;
			DeanieSettings.PetDamage = cfg.Bind<int>("Deanie", "PetDamage", DeanieSettings.PetDamage, "Damage per tick while being petted to death at the nest.").Value;
			DeanieSettings.PetTickInterval = cfg.Bind<float>("Deanie", "PetTickInterval", DeanieSettings.PetTickInterval, "Seconds between petting damage ticks.").Value;
			DeanieSettings.RevertAfterKill = cfg.Bind<bool>("Deanie", "RevertAfterKill", DeanieSettings.RevertAfterKill, "Turn cute again after killing someone, then wander off.").Value;
			DeanieSettings.CalmDownTime = cfg.Bind<float>("Deanie", "CalmDownTime", DeanieSettings.CalmDownTime, "Monster turns cute again after this many seconds with no target inside.").Value;
			DeanieSettings.RedEyeTimer = cfg.Bind<float>("Deanie", "RedEyeTimer", DeanieSettings.RedEyeTimer, "Once eyes go red, transform after this many seconds even if petting stops (0 = off). Visual twitch/red eyes stay; purr sound does not change.").Value;
			((EnemyAI)val.enemyPrefab.GetComponent<DeanieAI>()).enemyHP = DeanieSettings.MonsterHP;
			Enemies.RegisterEnemy(val, Rarity, (LevelTypes)1, val2, val3);
			DeanieType = val;
			new Harmony("rfgames.apollo11mod.deanie").PatchAll(typeof(DeanieRegistration));
			Plugin.Log.LogInfo((object)string.Format("Deanie registered (rarity {0}{1}).", Rarity, value ? $", TEST weight {TestRarity} on '{TestMoons}'" : ""));
		}

		[HarmonyPatch(typeof(RoundManager), "LoadNewLevel")]
		[HarmonyPrefix]
		private static void Inject(SelectableLevel newLevel)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			try
			{
				if ((Object)(object)DeanieType == (Object)null || (Object)(object)newLevel == (Object)null)
				{
					return;
				}
				int num = (MoonFeatures.MoonMatches(newLevel, TestMoons) ? TestRarity : (MoonFeatures.IsApollo(newLevel) ? Rarity : 0));
				SpawnableEnemyWithRarity val = ((IEnumerable<SpawnableEnemyWithRarity>)newLevel.Enemies).FirstOrDefault((Func<SpawnableEnemyWithRarity, bool>)((SpawnableEnemyWithRarity e) => e != null && (Object)(object)e.enemyType == (Object)(object)DeanieType));
				if (num <= 0)
				{
					if (val != null)
					{
						newLevel.Enemies.Remove(val);
					}
					return;
				}
				if (val == null)
				{
					val = new SpawnableEnemyWithRarity(DeanieType, num);
					newLevel.Enemies.Add(val);
				}
				val.rarity = num;
				Plugin.Log.LogInfo((object)$"Deanie weight {num} on '{newLevel.PlanetName}'.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Deanie Inject: " + ex));
			}
		}
	}
	internal static class DoppelRegistration
	{
		internal static EnemyType DoppelType;

		internal static int Rarity = 25;

		internal static int TestRarity = 1000;

		internal static string TestMoons = "";

		internal static void Register(AssetBundle bundle, ConfigFile cfg)
		{
			//IL_0424: Unknown result type (might be due to invalid IL or missing references)
			EnemyType val = bundle.LoadAsset<EnemyType>("DoppelEnemy");
			TerminalNode val2 = bundle.LoadAsset<TerminalNode>("DoppelTN");
			TerminalKeyword val3 = bundle.LoadAsset<TerminalKeyword>("DoppelTK");
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"DoppelEnemy not in bundle (build with Apollo11BuildDoppel) - Doppel disabled.");
				return;
			}
			NetworkPrefabs.RegisterNetworkPrefab(val.enemyPrefab);
			Rarity = cfg.Bind<int>("Doppel", "Rarity", 25, "Spawn weight inside the Lunar Base on 11 Apollo.").Value;
			val.MaxCount = cfg.Bind<int>("Doppel", "MaxCount", 1, "Max Doppels alive at once.").Value;
			bool value = cfg.Bind<bool>("Doppel", "TestForceSpawn", false, "TESTING: huge spawn weight + spawn from day start on TestMoons.").Value;
			TestRarity = cfg.Bind<int>("Doppel", "TestRarity", 1000, "Weight when TestForceSpawn is true.").Value;
			TestMoons = (value ? cfg.Bind<string>("Doppel", "TestMoons", "Apollo", "Planet-name fragments or All.").Value : "");
			if (value)
			{
				val.probabilityCurve = AnimationCurve.Constant(0f, 1f, 1f);
			}
			DoppelSettings.FollowDistance = cfg.Bind<float>("Doppel", "FollowDistance", DoppelSettings.FollowDistance, "How far from the group centre it idles.").Value;
			DoppelSettings.WalkSpeed = cfg.Bind<float>("Doppel", "WalkSpeed", DoppelSettings.WalkSpeed, "Speed while holding the flashlight.").Value;
			DoppelSettings.ApproachSpeed = cfg.Bind<float>("Doppel", "ApproachSpeed", DoppelSettings.ApproachSpeed, "Speed while sneaking with the shovel.").Value;
			DoppelSettings.CrouchSpeed = cfg.Bind<float>("Doppel", "CrouchSpeed", DoppelSettings.CrouchSpeed, "Speed of the final crouched sneak.").Value;
			DoppelSettings.CrouchSneakDistance = cfg.Bind<float>("Doppel", "CrouchSneakDistance", DoppelSettings.CrouchSneakDistance, "Crouches when this close to its victim.").Value;
			DoppelSettings.ShovelDamage = cfg.Bind<int>("Doppel", "ShovelDamage", DoppelSettings.ShovelDamage, "Damage of one sneak shovel hit.").Value;
			DoppelSettings.HitCooldown = cfg.Bind<float>("Doppel", "HitCooldown", DoppelSettings.HitCooldown, "Seconds between sneak attacks.").Value;
			DoppelSettings.LookFovDegrees = cfg.Bind<float>("Doppel", "LookFovDegrees", DoppelSettings.LookFovDegrees, "Camera cone (degrees) that counts as looking at the Doppel.").Value;
			DoppelSettings.EnableVoiceMimic = cfg.Bind<bool>("DoppelVoice", "EnableVoiceMimic", true, "Doppel repeats real players' recorded voice clips (memory only, never saved). Off = garbled radio clips only.").Value;
			DoppelSettings.VoiceUseOwnOnly = cfg.Bind<bool>("DoppelVoice", "VoiceUseOwnOnly", false, "Solo/testing: every client hears the Doppel replay ITS OWN player's voice instead of the copied player's.").Value;
			DoppelSettings.ShareVoiceClips = cfg.Bind<bool>("DoppelVoice", "ShareVoiceClips", true, "Send your own recorded clips to the other players (host relays). Off = your voice is only mimicked on your own machine.").Value;
			DoppelSettings.RecordOnlyWhileTransmitting = cfg.Bind<bool>("DoppelVoice", "RecordOnlyWhileTransmitting", true, "Only record while your voice chat is actually transmitting (respects push-to-talk / mute).").Value;
			DoppelSettings.MaxClipsPerPlayer = cfg.Bind<int>("DoppelVoice", "MaxClipsPerPlayer", 20, "Recent clips kept per player.").Value;
			DoppelSettings.MinClipLength = cfg.Bind<float>("DoppelVoice", "MinClipLength", 1f, "Shortest clip kept (s).").Value;
			DoppelSettings.MaxClipLength = cfg.Bind<float>("DoppelVoice", "MaxClipLength", 4f, "Longest clip (s); longer speech is split.").Value;
			DoppelSettings.VoiceVadThreshold = cfg.Bind<float>("DoppelVoice", "VoiceActivityThreshold", 0.012f, "RMS level counted as speech (lower = more sensitive).").Value;
			DoppelSettings.VoiceSendMinInterval = cfg.Bind<float>("DoppelVoice", "SendMinInterval", 2f, "Min seconds between uploading clips (rate limit, newest clip wins).").Value;
			DoppelSettings.VoiceIntervalMin = cfg.Bind<float>("DoppelVoice", "PlayIntervalMin", DoppelSettings.VoiceIntervalMin, "Min seconds between Doppel lines.").Value;
			DoppelSettings.VoiceIntervalMax = cfg.Bind<float>("DoppelVoice", "PlayIntervalMax", DoppelSettings.VoiceIntervalMax, "Max seconds between Doppel lines.").Value;
			DoppelSettings.NearPlayerIntervalMultiplier = cfg.Bind<float>("DoppelVoice", "NearPlayerIntervalMultiplier", 0.5f, "Interval multiplier when a player is within 12 m (talks more).").Value;
			DoppelSettings.MimicVoiceVolume = cfg.Bind<float>("DoppelVoice", "MimicVoiceVolume", 1f, "Volume of replayed voice clips.").Value;
			((EnemyAI)val.enemyPrefab.GetComponent<DoppelAI>()).enemyHP = DoppelSettings.MaxHP;
			Enemies.RegisterEnemy(val, Rarity, (LevelTypes)1, val2, val3);
			DoppelType = val;
			new Harmony("rfgames.apollo11mod.doppel").PatchAll(typeof(DoppelRegistration));
			Plugin.Log.LogInfo((object)string.Format("Doppel registered (rarity {0}{1}).", Rarity, value ? $", TEST weight {TestRarity} on '{TestMoons}'" : ""));
		}

		[HarmonyPatch(typeof(RoundManager), "LoadNewLevel")]
		[HarmonyPrefix]
		private static void Inject(SelectableLevel newLevel)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			try
			{
				if ((Object)(object)DoppelType == (Object)null || (Object)(object)newLevel == (Object)null)
				{
					return;
				}
				int num = (MoonFeatures.MoonMatches(newLevel, TestMoons) ? TestRarity : (MoonFeatures.IsApollo(newLevel) ? Rarity : 0));
				SpawnableEnemyWithRarity val = ((IEnumerable<SpawnableEnemyWithRarity>)newLevel.Enemies).FirstOrDefault((Func<SpawnableEnemyWithRarity, bool>)((SpawnableEnemyWithRarity e) => e != null && (Object)(object)e.enemyType == (Object)(object)DoppelType));
				if (num <= 0)
				{
					if (val != null)
					{
						newLevel.Enemies.Remove(val);
					}
					return;
				}
				if (val == null)
				{
					val = new SpawnableEnemyWithRarity(DoppelType, num);
					newLevel.Enemies.Add(val);
				}
				val.rarity = num;
				Plugin.Log.LogInfo((object)$"Doppel weight {num} on '{newLevel.PlanetName}'.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Doppel Inject: " + ex));
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "Start")]
	internal static class DoppelVoiceHooks
	{
		[HarmonyPostfix]
		private static void Postfix(StartOfRound __instance)
		{
			try
			{
				if (DoppelSettings.EnableVoiceMimic)
				{
					if ((Object)(object)((Component)__instance).GetComponent<DoppelVoiceRunner>() == (Object)null)
					{
						((Component)__instance).gameObject.AddComponent<DoppelVoiceRunner>();
					}
					DoppelVoice.Init();
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("DoppelVoice hook: " + ex));
			}
		}
	}
	internal static class GoldScrapRegistration
	{
		internal static readonly List<Item> Items = new List<Item>();

		internal static int ApolloRarity = 3;

		internal static int VanillaRarity = 1;

		internal static int MaxPerRound = 3;

		internal static string VanillaMoons = "";

		internal static bool TestForceSpawn;

		internal static int TestCount = 4;

		internal static string TestMoons = "Apollo";

		private static string lastKey;

		internal static void Register(AssetBundle bundle, ConfigFile cfg)
		{
			//IL_03c2: Unknown result type (might be due to invalid IL or missing references)
			if (!cfg.Bind<bool>("GoldScrap", "Enabled", true, "Add cursed gold scrap (golden vanilla scrap that whispers and explodes if held too long).").Value)
			{
				return;
			}
			GoldScrapSettings.FixedValue = Math.Max(1, cfg.Bind<int>("GoldScrap", "Value", 500, "Fixed sell value (credits) of every gold item, independent of the moon's scrap multiplier.").Value);
			ApolloRarity = cfg.Bind<int>("GoldScrap", "ApolloRarity", 3, "Spawn weight of EACH gold item on 11 Apollo (13 items; the moon's normal scrap pool weighs ~570, so 3 = about 1 gold item per round).").Value;
			VanillaRarity = cfg.Bind<int>("GoldScrap", "VanillaRarity", 1, "Spawn weight of EACH gold item on the moons listed in VanillaMoons (1 = roughly one gold item every 4-5 days).").Value;
			MaxPerRound = cfg.Bind<int>("GoldScrap", "MaxPerRound", 3, "Host: at most this many gold items are spawned inside the facility per round; extras are removed right after scrap spawning. 0 = no cap.").Value;
			VanillaMoons = cfg.Bind<string>("GoldScrap", "VanillaMoons", "Experimentation,Assurance,Vow,Offense,March,Adamance,Rend,Dine,Titan,Artifice,Embrion", "Comma-separated planet-name fragments (or All, or empty for none) where gold scrap also spawns with VanillaRarity. Remove a moon to turn it off.").Value;
			GoldScrapSettings.FuseMin = cfg.Bind<float>("GoldScrap", "FuseMin", 20f, "Shortest hidden fuse (s of continuous holding). Rerolled on every pickup.").Value;
			GoldScrapSettings.FuseMax = cfg.Bind<float>("GoldScrap", "FuseMax", 60f, "Longest hidden fuse (s).").Value;
			GoldScrapSettings.WarningSeconds = cfg.Bind<float>("GoldScrap", "WarningSeconds", 5f, "Accelerating beeps for this many seconds before it explodes.").Value;
			GoldScrapSettings.HeldMeansInInventory = cfg.Bind<bool>("GoldScrap", "HeldMeansInInventory", false, "false = the fuse only runs while it is the item in your hands (pocketing it resets the fuse like dropping). true = runs while it is anywhere in your inventory.").Value;
			GoldScrapSettings.WhisperIntervalMin = cfg.Bind<float>("GoldScrap", "WhisperIntervalMin", 7f, "Min seconds between whispers while held.").Value;
			GoldScrapSettings.WhisperIntervalMax = cfg.Bind<float>("GoldScrap", "WhisperIntervalMax", 18f, "Max seconds between whispers while held.").Value;
			GoldScrapSettings.WhisperVolume = cfg.Bind<float>("GoldScrap", "WhisperVolume", 0.75f, "Whisper volume in the holder's ear.").Value;
			GoldScrapSettings.OthersHearWhispers = cfg.Bind<bool>("GoldScrap", "OthersHearWhispers", true, "Nearby players faintly hear the whispers (3D, short range).").Value;
			GoldScrapSettings.KillRange = cfg.Bind<float>("GoldScrap", "KillRange", 5.7f, "Explosion kill radius (landmine = 5.7).").Value;
			GoldScrapSettings.DamageRange = cfg.Bind<float>("GoldScrap", "DamageRange", 6.4f, "Explosion damage radius (landmine = 6.4).").Value;
			GoldScrapSettings.NonLethalDamage = cfg.Bind<int>("GoldScrap", "NonLethalDamage", 50, "Damage between kill and damage radius.").Value;
			TestForceSpawn = cfg.Bind<bool>("GoldScrap", "TestForceSpawn", false, "TESTING: host spawns TestCount gold items just inside the main entrance on TestMoons.").Value;
			TestCount = cfg.Bind<int>("GoldScrap", "TestCount", 4, "TESTING: how many gold items to spawn.").Value;
			TestMoons = cfg.Bind<string>("GoldScrap", "TestMoons", "Apollo", "TESTING: planet-name fragments (or All) for TestForceSpawn.").Value;
			int maxValue = Mathf.RoundToInt((float)GoldScrapSettings.FixedValue / 0.4f);
			Item[] array = bundle.LoadAllAssets<Item>();
			foreach (Item val in array)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.spawnPrefab == (Object)null) && !((Object)(object)val.spawnPrefab.GetComponent<CursedGoldItem>() == (Object)null))
				{
					val.minValue = (val.maxValue = maxValue);
					Utilities.FixMixerGroups(val.spawnPrefab);
					NetworkPrefabs.RegisterNetworkPrefab(val.spawnPrefab);
					Items.RegisterScrap(val, 0, (LevelTypes)1);
					Items.Add(val);
				}
			}
			if (Items.Count == 0)
			{
				Plugin.Log.LogError((object)"No gold scrap items in the bundle.");
				return;
			}
			Plugin.Log.LogInfo((object)string.Format("Gold scrap: {0} items ({1}), value {2}.", Items.Count, string.Join(", ", Items.Select((Item val2) => val2.itemName)), GoldScrapSettings.FixedValue));
			new Harmony("rfgames.apollo11mod.goldscrap").PatchAll(typeof(GoldScrapRegistration));
		}

		[HarmonyPatch(typeof(RoundManager), "LoadNewLevel")]
		[HarmonyPrefix]
		private static void Inject(SelectableLevel newLevel)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			try
			{
				if ((Object)(object)newLevel == (Object)null || newLevel.spawnableScrap == null)
				{
					return;
				}
				int num = (MoonFeatures.IsApollo(newLevel) ? ApolloRarity : (MoonFeatures.MoonMatches(newLevel, VanillaMoons) ? VanillaRarity : 0));
				newLevel.spawnableScrap.RemoveAll((SpawnableItemWithRarity s) => s != null && Items.Contains(s.spawnableItem));
				if (num <= 0)
				{
					return;
				}
				foreach (Item item in Items)
				{
					newLevel.spawnableScrap.Add(new SpawnableItemWithRarity(item, num));
				}
				Plugin.Log.LogInfo((object)$"Gold scrap weight {num} x{Items.Count} on '{newLevel.PlanetName}'.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("GoldScrap inject: " + ex));
			}
		}

		[HarmonyPatch(typeof(GrabbableObject), "SetScrapValue")]
		[HarmonyPostfix]
		private static void FixValue(GrabbableObject __instance)
		{
			if (__instance is CursedGoldItem && __instance.scrapValue != GoldScrapSettings.FixedValue)
			{
				__instance.scrapValue = GoldScrapSettings.FixedValue;
				ScanNodeProperties componentInChildren = ((Component)__instance).GetComponentInChildren<ScanNodeProperties>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					componentInChildren.subText = $"Value: ${GoldScrapSettings.FixedValue}";
					componentInChildren.scrapValue = GoldScrapSettings.FixedValue;
				}
			}
		}

		[HarmonyPatch(typeof(RoundManager), "SpawnScrapInLevel")]
		[HarmonyPostfix]
		[HarmonyPriority(800)]
		private static void CapPerRound(RoundManager __instance)
		{
			try
			{
				if (MaxPerRound <= 0 || TestForceSpawn || !((NetworkBehaviour)__instance).IsServer)
				{
					return;
				}
				List<CursedGoldItem> list = (from g in Object.FindObjectsOfType<CursedGoldItem>()
					where (Object)(object)g != (Object)null && ((GrabbableObject)g).isInFactory && !((GrabbableObject)g).isInShipRoom && !((GrabbableObject)g).isHeld && (Object)(object)((GrabbableObject)g).playerHeldBy == (Object)null
					select g).ToList();
				if (list.Count <= MaxPerRound)
				{
					if (list.Count > 0)
					{
						Plugin.Log.LogInfo((object)$"Gold scrap this round: {list.Count} (cap {MaxPerRound}).");
					}
					return;
				}
				List<CursedGoldItem> list2 = list.OrderBy((CursedGoldItem _) => Random.value).Skip(MaxPerRound).ToList();
				foreach (CursedGoldItem item in list2)
				{
					NetworkObject component = ((Component)item).GetComponent<NetworkObject>();
					if ((Object)(object)component != (Object)null && component.IsSpawned)
					{
						component.Despawn(true);
					}
					else
					{
						Object.Destroy((Object)(object)((Component)item).gameObject);
					}
				}
				Plugin.Log.LogInfo((object)$"Gold scrap this round: {list.Count} rolled, {list2.Count} removed (cap {MaxPerRound}).");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("GoldScrap cap: " + ex));
			}
		}

		[HarmonyPatch(typeof(RoundManager), "SpawnScrapInLevel")]
		[HarmonyPostfix]
		private static void TestSpawn(RoundManager __instance)
		{
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: 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_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: 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)
			try
			{
				if (!TestForceSpawn || Items.Count == 0 || !((NetworkBehaviour)__instance).IsServer)
				{
					return;
				}
				SelectableLevel currentLevel = __instance.currentLevel;
				if ((Object)(object)currentLevel == (Object)null || !MoonFeatures.MoonMatches(currentLevel, TestMoons))
				{
					return;
				}
				string text = currentLevel.levelID + ":" + StartOfRound.Instance.randomMapSeed;
				if (text == lastKey)
				{
					return;
				}
				lastKey = text;
				EntranceTeleport val = ((IEnumerable<EntranceTeleport>)Object.FindObjectsOfType<EntranceTeleport>()).FirstOrDefault((Func<EntranceTeleport, bool>)((EntranceTeleport e) => e.entranceId == 0 && !e.isEntranceToBuilding));
				if ((Object)(object)val == (Object)null || (Object)(object)val.entrancePoint == (Object)null)
				{
					Plugin.Log.LogWarning((object)"[GoldTest] no main entrance.");
					return;
				}
				Vector3 position = val.entrancePoint.position;
				for (int num = 0; num < TestCount; num++)
				{
					Item val2 = Items[(num + Random.Range(0, Items.Count)) % Items.Count];
					Vector3 val3 = __instance.GetRandomNavMeshPositionInRadius(position + val.entrancePoint.forward * 2.5f, 2.5f, default(NavMeshHit)) + Vector3.up * 0.5f;
					GameObject obj = Object.Instantiate<GameObject>(val2.spawnPrefab, val3, Quaternion.identity, __instance.spawnedScrapContainer);
					GrabbableObject component = obj.GetComponent<GrabbableObject>();
					component.fallTime = 0f;
					component.isInFactory = true;
					component.SetScrapValue(GoldScrapSettings.FixedValue);
					obj.GetComponent<NetworkObject>().Spawn(false);
					Plugin.Log.LogInfo((object)$"[GoldTest] spawned {val2.itemName} at {val3} ({Vector3.Distance(val3, position):F1} m from main entrance inside).");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[GoldTest] failed: " + ex));
			}
		}
	}
	internal static class LllPreRegisterFix
	{
		private static bool hookedRecovery;

		private static RuntimeAnimatorController cachedStub;

		internal static void ApplyPatches(Harmony harmony)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Expected O, but got Unknown
			int num = 0;
			BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
			MethodInfo[] methods = typeof(ExtendedMod).GetMethods(bindingFlags);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name != "RegisterExtendedContent" || methodInfo.IsGenericMethodDefinition)
				{
					continue;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length == 1)
				{
					harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(LllPreRegisterFix), "PrefixObject", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogInfo((object)("[Apollo11] LllPreRegisterFix patched ExtendedMod." + methodInfo.Name + "(" + parameters[0].ParameterType.Name + ")"));
					}
					num++;
				}
			}
			Type type = AccessTools.TypeByName("LethalLevelLoader.LethalBundleManager");
			if (type != null)
			{
				methods = type.GetMethods(bindingFlags | BindingFlags.Static);
				foreach (MethodInfo methodInfo2 in methods)
				{
					if (methodInfo2.Name != "RegisterExtendedMod")
					{
						continue;
					}
					ParameterInfo[] parameters2 = methodInfo2.GetParameters();
					if (parameters2.Length >= 1 && typeof(ExtendedMod).IsAssignableFrom(parameters2[0].ParameterType))
					{
						harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(LllPreRegisterFix), "PrefixObject", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						ManualLogSource log2 = Plugin.Log;
						if (log2 != null)
						{
							log2.LogInfo((object)"[Apollo11] LllPreRegisterFix patched LethalBundleManager.RegisterExtendedMod");
						}
						num++;
					}
				}
			}
			if (num == 0)
			{
				ManualLogSource log3 = Plugin.Log;
				if (log3 != null)
				{
					log3.LogError((object)"[Apollo11] LllPreRegisterFix: no LLL register methods found to patch.");
				}
			}
			HookRecovery();
		}

		private static void HookRecovery()
		{
			if (hookedRecovery)
			{
				return;
			}
			hookedRecovery = true;
			try
			{
				Plugin.onSetupComplete += TryRecoverApollo;
				if (Plugin.IsSetupComplete)
				{
					TryRecoverApollo();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Apollo11] LllPreRegisterFix recovery hook failed: " + ex.Message));
				}
			}
		}

		private static void TryRecoverApollo()
		{
			try
			{
				foreach (ExtendedLevel extendedLevel in PatchedContent.ExtendedLevels)
				{
					if ((Object)(object)((extendedLevel != null) ? extendedLevel.SelectableLevel : null) != (Object)null && MoonFeatures.IsApollo(extendedLevel.SelectableLevel))
					{
						return;
					}
				}
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"[Apollo11] 11 Apollo not in LLL ExtendedLevels after setup — attempting recovery re-register.");
				}
				ExtendedMod val = null;
				ExtendedMod[] array = Resources.FindObjectsOfTypeAll<ExtendedMod>();
				foreach (ExtendedMod val2 in array)
				{
					if (!((Object)(object)val2 == (Object)null) && val2.ModName != null && val2.ModName.IndexOf("Apollo", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						val = val2;
						break;
					}
				}
				if ((Object)(object)val == (Object)null)
				{
					ManualLogSource log2 = Plugin.Log;
					if (log2 != null)
					{
						log2.LogError((object)"[Apollo11] Recovery: Apollo ExtendedMod not found in memory.");
					}
					return;
				}
				List<ExtendedLevel> list = new List<ExtendedLevel>();
				if (val.ExtendedLevels != null)
				{
					foreach (ExtendedLevel extendedLevel2 in val.ExtendedLevels)
					{
						if ((Object)(object)((extendedLevel2 != null) ? extendedLevel2.SelectableLevel : null) != (Object)null && MoonFeatures.IsApollo(extendedLevel2.SelectableLevel))
						{
							list.Add(extendedLevel2);
						}
					}
				}
				if (list.Count == 0)
				{
					ExtendedLevel[] array2 = Resources.FindObjectsOfTypeAll<ExtendedLevel>();
					foreach (ExtendedLevel val3 in array2)
					{
						if (!((Object)(object)((val3 != null) ? val3.SelectableLevel : null) == (Object)null) && MoonFeatures.IsApollo(val3.SelectableLevel))
						{
							list.Add(val3);
						}
					}
				}
				if (list.Count == 0)
				{
					ManualLogSource log3 = Plugin.Log;
					if (log3 != null)
					{
						log3.LogError((object)"[Apollo11] Recovery: no Apollo ExtendedLevel in memory.");
					}
					return;
				}
				MethodInfo method = typeof(ExtendedMod).GetMethod("RegisterExtendedContent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(ExtendedLevel) }, null);
				if (method == null)
				{
					ManualLogSource log4 = Plugin.Log;
					if (log4 != null)
					{
						log4.LogError((object)"[Apollo11] Recovery: RegisterExtendedContent(ExtendedLevel) not found.");
					}
					return;
				}
				foreach (ExtendedLevel item in list)
				{
					FixPlanet(item.SelectableLevel);
					try
					{
						method.Invoke(val, new object[1] { item });
						ManualLogSource log5 = Plugin.Log;
						if (log5 != null)
						{
							log5.LogInfo((object)("[Apollo11] Recovery: re-registered " + ((Object)item).name));
						}
					}
					catch (Exception ex)
					{
						ManualLogSource log6 = Plugin.Log;
						if (log6 != null)
						{
							log6.LogError((object)("[Apollo11] Recovery re-register failed: " + (ex.InnerException ?? ex)));
						}
					}
				}
			}
			catch (Exception ex2)
			{
				ManualLogSource log7 = Plugin.Log;
				if (log7 != null)
				{
					log7.LogError((object)("[Apollo11] TryRecoverApollo: " + ex2));
				}
			}
		}

		private static void PrefixObject(object __0)
		{
			try
			{
				ExtendedLevel val = (ExtendedLevel)((__0 is ExtendedLevel) ? __0 : null);
				if (val != null)
				{
					FixPlanet(val.SelectableLevel);
					return;
				}
				ExtendedMod val2 = (ExtendedMod)((__0 is ExtendedMod) ? __0 : null);
				if (val2 == null)
				{
					return;
				}
				List<ExtendedLevel> extendedLevels = val2.ExtendedLevels;
				if (extendedLevels == null)
				{
					return;
				}
				foreach (ExtendedLevel item in extendedLevels)
				{
					if ((Object)(object)item != (Object)null)
					{
						FixPlanet(item.SelectableLevel);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)("[Apollo11] LllPreRegisterFix: " + ex));
				}
			}
		}

		internal static void FixPlanet(SelectableLevel sl)
		{
			GameObject val = sl?.planetPrefab;
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			VanillaRefs component = val.GetComponent<VanillaRefs>();
			if ((Object)(object)component != (Object)null)
			{
				component.resolved = false;
				component.Resolve();
			}
			Animator val2 = val.GetComponent<Animator>() ?? val.GetComponentInChildren<Animator>(true);
			if ((Object)(object)val2 == (Object)null)
			{
				return;
			}
			if ((Object)(object)val2.runtimeAnimatorController != (Object)null)
			{
				RuntimeAnimatorController runtimeAnimatorController = val2.runtimeAnimatorController;
				AnimatorOverrideController val3 = (AnimatorOverrideController)(object)((runtimeAnimatorController is AnimatorOverrideController) ? runtimeAnimatorController : null);
				if (val3 == null || !((Object)(object)val3.runtimeAnimatorController == (Object)null))
				{
					return;
				}
			}
			RuntimeAnimatorController val4 = FindUsableController();
			if ((Object)(object)val4 == (Object)null)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)"[Apollo11] Planet animator: no RuntimeAnimatorController available for LLL registration (GasGiant/Deanie/Airlock none loaded).");
				}
				return;
			}
			val2.runtimeAnimatorController = val4;
			ManualLogSource log2 = Plugin.Log;
			if (log2 != null)
			{
				log2.LogInfo((object)("[Apollo11] Planet animator: assigned '" + ((Object)val4).name + "' before LLL registration."));
			}
		}

		private static RuntimeAnimatorController FindUsableController()
		{
			if ((Object)(object)cachedStub != (Object)null)
			{
				return cachedStub;
			}
			RuntimeAnimatorController[] array = Resources.FindObjectsOfTypeAll<RuntimeAnimatorController>().Where(delegate(RuntimeAnimatorController c)
			{
				if ((Object)(object)c != (Object)null)
				{
					AnimatorOverrideController val4 = (AnimatorOverrideController)(object)((c is AnimatorOverrideController) ? c : null);
					if (val4 != null)
					{
						return !((Object)(object)val4.runtimeAnimatorController == (Object)null);
					}
					return true;
				}
				return false;
			}).ToArray();
			RuntimeAnimatorController val = Pick(array, (RuntimeAnimatorController c) => ((Object)c).name == "GasGiant") ?? Pick(array, (RuntimeAnimatorController c) => ((Object)c).name != null && ((Object)c).name.StartsWith("Apollo11Planet", StringComparison.Ordinal)) ?? Pick(array, (RuntimeAnimatorController c) => ((Object)c).name != null && (((Object)c).name.StartsWith("Deanie", StringComparison.Ordinal) || ((Object)c).name.StartsWith("LB_", StringComparison.Ordinal) || ((Object)c).name.StartsWith("Apollo11", StringComparison.Ordinal))) ?? array.FirstOrDefault();
			if ((Object)(object)val == (Object)null && (Object)(object)Plugin.Bundle != (Object)null)
			{
				string[] allAssetNames = Plugin.Bundle.GetAllAssetNames();
				foreach (string text in allAssetNames)
				{
					if (text != null && (text.EndsWith(".controller", StringComparison.OrdinalIgnoreCase) || text.Contains("deanie") || text.Contains("anim")))
					{
						RuntimeAnimatorController val2 = Plugin.Bundle.LoadAsset<RuntimeAnimatorController>(text);
						if ((Object)(object)val2 != (Object)null)
						{
							val = val2;
							break;
						}
					}
				}
				if ((Object)(object)val == (Object)null)
				{
					RuntimeAnimatorController[] array2 = Plugin.Bundle.LoadAllAssets<RuntimeAnimatorController>();
					foreach (RuntimeAnimatorController val3 in array2)
					{
						if ((Object)(object)val3 != (Object)null)
						{
							val = val3;
							break;
						}
					}
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				cachedStub = val;
			}
			return val;
			static RuntimeAnimatorController Pick(IEnumerable<RuntimeAnimatorController> all, Func<RuntimeAnimatorController, bool> pred)
			{
				return all.FirstOrDefault((Func<RuntimeAnimatorController, bool>)((RuntimeAnimatorController c) => Object.op_Implicit((Object)(object)c) && pred(c)));
			}
		}
	}
	internal static class MoonFeatures
	{
		internal static EnemyType CrackType;

		internal static int ApolloRarity = 40;

		internal static int TestRarity = 1000;

		internal static string TestMoons = "";

		internal static bool LowGravity = true;

		internal static float GravityScale = 0.65f;

		internal static bool IsApollo(SelectableLevel l)
		{
			if ((Object)(object)l != (Object)null && l.PlanetName != null)
			{
				return l.PlanetName.IndexOf("Apollo", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		internal static bool MoonMatches(SelectableLevel l, string list)
		{
			if ((Object)(object)l == (Object)null || string.IsNullOrWhiteSpace(list))
			{
				return false;
			}
			if (list.Trim().Equals("All", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			return (from s in list.Split(',')
				select s.Trim() into s
				where s.Length > 0
				select s).Any((string s) => l.PlanetName.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0);
		}

		[HarmonyPatch(typeof(RoundManager), "LoadNewLevel")]
		[HarmonyPrefix]
		private static void InjectCrack(SelectableLevel newLevel)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			try
			{
				if ((Object)(object)CrackType == (Object)null || (Object)(object)newLevel == (Object)null)
				{
					return;
				}
				int num = (MoonMatches(newLevel, TestMoons) ? TestRarity : (IsApollo(newLevel) ? ApolloRarity : 0));
				SpawnableEnemyWithRarity val = ((IEnumerable<SpawnableEnemyWithRarity>)newLevel.Enemies).FirstOrDefault((Func<SpawnableEnemyWithRarity, bool>)((SpawnableEnemyWithRarity e) => e != null && (Object)(object)e.enemyType == (Object)(object)CrackType));
				if (num <= 0)
				{
					if (val != null)
					{
						newLevel.Enemies.Remove(val);
					}
					return;
				}
				if (val == null)
				{
					val = new SpawnableEnemyWithRarity(CrackType, num);
					newLevel.Enemies.Add(val);
				}
				val.rarity = num;
				Plugin.Log.LogInfo((object)$"Wall Crack weight {num} on '{newLevel.PlanetName}'.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("InjectCrack: " + ex));
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "Update")]
		[HarmonyPostfix]
		private static void LunarGravity(PlayerControllerB __instance)
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null || !IsApollo(instance.currentLevel) || instance.inShipPhase)
			{
				return;
			}
			GameNetworkManager instance2 = GameNetworkManager.Instance;
			if (!((Object)(object)instance2 == (Object)null) && !((Object)(object)__instance != (Object)(object)instance2.localPlayerController))
			{
				MoonFog.Tick(__instance.isInsideFactory);
				if (!__instance.isInsideFactory && !__instance.isPlayerDead && !__instance.isClimbingLadder && !__instance.isUnderwater && __instance.isPlayerControlled && LowGravity && !(GravityScale >= 0.999f) && !((Object)(object)__instance.thisController == (Object)null) && !__instance.thisController.isGrounded && !__instance.isInHangarShipRoom)
				{
					float num = 1f - GravityScale;
					float deltaTime = Time.deltaTime;
					__instance.fallValue = Mathf.Min(__instance.fallValue + 38f * num * deltaTime, __instance.jumpForce);
					__instance.fallValueUncapped += 38f * num * deltaTime;
				}
			}
		}
	}
	internal static class MoonFog
	{
		internal static bool Enabled = true;

		private static Volume vol;

		internal static void Init()
		{
			SceneManager.sceneLoaded += OnSceneLoaded;
		}

		private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			if (!Enabled || ((Scene)(ref scene)).name != "Apollo11Level")
			{
				return;
			}
			int num = 0;
			GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
			for (int i = 0; i < rootGameObjects.Length; i++)
			{
				LocalVolumetricFog[] componentsInChildren = rootGameObjects[i].GetComponentsInChildren<LocalVolumetricFog>(true);
				for (int j = 0; j < componentsInChildren.Length; j++)
				{
					((Behaviour)componentsInChildren[j]).enabled = false;
					num++;
				}
			}
			GameObject val = new GameObject("Apollo11_NoFogVolume");
			SceneManager.MoveGameObjectToScene(val, scene);
			vol = val.AddComponent<Volume>();
			vol.isGlobal = true;
			vol.priority = 1000f;
			vol.weight = 1f;
			VolumeProfile val2 = ScriptableObject.CreateInstance<VolumeProfile>();
			Fog obj = val2.Add<Fog>(true);
			((VolumeParameter<bool>)(object)obj.enabled).Override(false);
			((VolumeParameter<bool>)(object)obj.enableVolumetricFog).Override(false);
			((VolumeParameter<bool>)(object)val2.Add<VolumetricClouds>(true).enable).Override(false);
			vol.sharedProfile = val2;
			Plugin.Log.LogInfo((object)$"MoonFog: no-fog volume added on {((Scene)(ref scene)).name}, disabled {num} LocalVolumetricFog.");
		}

		internal static void Tick(bool inside)
		{
			if ((Object)(object)vol != (Object)null)
			{
				vol.weight = (inside ? 0f : 1f);
			}
		}
	}
	[BepInPlugin("rfgames.apollo11mod", "Apollo 11", "1.0.4")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		internal static AssetBundle Bundle;

		private const string BundleName = "apollo11assets";

		private void Awake()
		{
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: 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)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: 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_013b: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			InitNetcodePatcher();
			string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "apollo11assets");
			if (!File.Exists(text))
			{
				Log.LogError((object)("Asset bundle not found at " + text + ". Build it in Unity first (see README)."));
				return;
			}
			Bundle = AssetBundle.LoadFromFile(text);
			RegisterWallCrack();
			DeanieRegistration.Register(Bundle, ((BaseUnityPlugin)this).Config);
			DoppelRegistration.Register(Bundle, ((BaseUnityPlugin)this).Config);
			GoldScrapRegistration.Register(Bundle, ((BaseUnityPlugin)this).Config);
			SuitsRegistration.Register(Bundle, ((BaseUnityPlugin)this).Config);
			ZombieRegistration.Register(Bundle, ((BaseUnityPlugin)this).Config);
			new Harmony("rfgames.apollo11mod").PatchAll(typeof(TestSpawner));
			new Harmony("rfgames.apollo11mod.deanietest").PatchAll(typeof(TestSpawnerDeanie));
			new Harmony("rfgames.apollo11mod.doppeltest").PatchAll(typeof(TestSpawnerDoppel));
			new Harmony("rfgames.apollo11mod.doppelvoice").PatchAll(typeof(DoppelVoiceHooks));
			new Harmony("rfgames.apollo11mod.vanillarefs").PatchAll(typeof(VanillaAssetHooks));
			LllPreRegisterFix.ApplyPatches(new Harmony("rfgames.apollo11mod.lllprereg"));
			Log.LogInfo((object)"Apollo 11 1.0.4 loaded.");
		}

		private void RegisterWallCrack()
		{
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			EnemyType val = Bundle.LoadAsset<EnemyType>("WallCrackEnemy");
			TerminalNode val2 = Bundle.LoadAsset<TerminalNode>("WallCrackTN");
			TerminalKeyword val3 = Bundle.LoadAsset<TerminalKeyword>("WallCrackTK");
			if ((Object)(object)val == (Object)null)
			{
				Log.LogError((object)"WallCrackEnemy not in bundle.");
				return;
			}
			NetworkPrefabs.RegisterNetworkPrefab(val.enemyPrefab);
			int value = ((BaseUnityPlugin)this).Config.Bind<int>("WallCrack", "Rarity", 40, "Spawn weight of the Wall Crack inside the Lunar Base on 11 Apollo (the only moon it spawns on in normal play).").Value;
			bool value2 = ((BaseUnityPlugin)this).Config.Bind<bool>("Testing", "ForceSpawn", false, "TESTING: give the Wall Crack a huge spawn weight on the ForceSpawnMoons. Set false for normal play.").Value;
			int value3 = ((BaseUnityPlugin)this).Config.Bind<int>("Testing", "ForceSpawnRarity", 1000, "Spawn weight used when ForceSpawn is true.").Value;
			string value4 = ((BaseUnityPlugin)this).Config.Bind<string>("Testing", "ForceSpawnMoons", "Experimentation,Apollo", "Comma-separated planet-name fragments that get the forced weight / test spawns (e.g. Experimentation,Apollo), or All.").Value;
			int value5 = ((BaseUnityPlugin)this).Config.Bind<int>("Testing", "MaxCount", 2, "Max Wall Cracks alive at once.").Value;
			val.MaxCount = value5;
			TestSpawner.CrackType = val;
			TestSpawner.Moons = value4;
			TestSpawner.Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Testing", "SpawnOnLevelLoad", false, "TESTING: host spawns Count Wall Cracks near the main entrance (inside) as soon as the interior has generated (ForceSpawnMoons only).").Value;
			TestSpawner.Count = ((BaseUnityPlugin)this).Config.Bind<int>("Testing", "Count", 3, "How many Wall Cracks SpawnOnLevelLoad spawns.").Value;
			WallCrackAI.ShowDebugMarker = ((BaseUnityPlugin)this).Config.Bind<bool>("Testing", "DebugMarker", false, "TESTING: show a bright green sphere + light at each Wall Crack's final position.").Value;
			Log.LogInfo((object)$"Testing: DebugMarker={WallCrackAI.ShowDebugMarker}, SpawnOnLevelLoad={TestSpawner.Enabled}, Count={TestSpawner.Count}, moons={value4}");
			if (value2)
			{
				val.probabilityCurve = AnimationCurve.Constant(0f, 1f, 1f);
				Log.LogWarning((object)$"TESTING: Wall Crack forced spawn weight {value3} on '{value4}'.");
			}
			Enemies.RegisterEnemy(val, value, (LevelTypes)1, val2, val3);
			MoonFeatures.CrackType = val;
			MoonFeatures.ApolloRarity = value;
			MoonFeatures.TestMoons = (value2 ? value4 : "");
			MoonFeatures.TestRarity = value3;
			MoonFeatures.LowGravity = ((BaseUnityPlugin)this).Config.Bind<bool>("Moon", "LowGravity", true, "Lower gravity while outdoors on 11 Apollo.").Value;
			MoonFeatures.GravityScale = Mathf.Clamp(((BaseUnityPlugin)this).Config.Bind<float>("Moon", "GravityScale", 0.65f, "Fraction of normal gravity outdoors on 11 Apollo (1 = vanilla). 0.65 = ~1.5x jump height, slower falls.").Value, 0.3f, 1f);
			new Harmony("rfgames.apollo11mod.moon").PatchAll(typeof(MoonFeatures));
			bool value6 = ((BaseUnityPlugin)this).Config.Bind<bool>("Testing", "FreeRoute", false, "TESTING: make the route to 11 Apollo free (overrides [Moon] RoutePrice).").Value;
			int value7 = ((BaseUnityPlugin)this).Config.Bind<int>("Moon", "RoutePrice", 250, "Route price to 11 Apollo in normal play.").Value;
			LaserBridge.CycleEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Bridge", "BridgeEnabled", true, "Timed hard-light bridge over the hatch chasm on 11 Apollo. false = the bridge stays on (solid) all day. The host's settings are used.").Value;
			LaserBridge.OnTime = Mathf.Clamp(((BaseUnityPlugin)this).Config.Bind<float>("Bridge", "BridgeOnTime", 5.5f, "Seconds the bridge is steady and solid. Default = 1.8 x the ~3.05 s standing-start sprint across the 26 m deck. The bridge stays solid through the warning too.").Value, 1f, 120f);
			LaserBridge.WarningTime = Mathf.Clamp(((BaseUnityPlugin)this).Config.Bind<float>("Bridge", "BridgeWarningTime", 3f, "Seconds of warning (still solid: flicker, rising beeps, amber then red pylon lights) before it switches off.").Value, 0.5f, 30f);
			LaserBridge.OffTime = Mathf.Clamp(((BaseUnityPlugin)this).Config.Bind<float>("Bridge", "BridgeOffTime", 8f, "Seconds the bridge is OFF (no deck: anyone on it falls). Includes the 1.5 s power-up flicker at the end.").Value, 2f, 120f);
			MoonFog.Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Moon", "NoFog", true, "Remove all fog/haze outdoors on 11 Apollo.").Value;
			MoonFog.Init();
			RoutePriceOverride.Price = ((!value6) ? Math.Max(0, value7) : 0);
			if (Chainloader.PluginInfos.ContainsKey("imabatby.lethallevelloader"))
			{
				HookRoutePrice();
			}
			else
			{
				Log.LogWarning((object)"LethalLevelLoader not found - route price override disabled.");
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void HookRoutePrice()
		{
			RoutePriceOverride.Hook();
		}

		private static void InitNetcodePatcher()
		{
			Type[] types = Assembly.GetExecutingAssembly().GetTypes();
			for (int i = 0; i < types.Length; i++)
			{
				MethodInfo[] methods = types[i].GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo in methods)
				{
					if (methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false).Length != 0)
					{
						methodInfo.Invoke(null, null);
					}
				}
			}
		}
	}
	internal static class RoutePriceOverride
	{
		internal static int Price = 250;

		internal static void Hook()
		{
			Plugin.onSetupComplete += Apply;
			Plugin.onLobbyInitialized += Apply;
			if (Plugin.IsSetupComplete)
			{
				Apply();
			}
		}

		private static void Apply()
		{
			try
			{
				bool flag = false;
				foreach (ExtendedLevel extendedLevel in PatchedContent.ExtendedLevels)
				{
					SelectableLevel val = ((extendedLevel != null) ? extendedLevel.SelectableLevel : null);
					if (!((Object)(object)val == (Object)null) && MoonFeatures.IsApollo(val))
					{
						extendedLevel.RoutePrice = Price;
						flag = true;
						Plugin.Log.LogInfo((object)$"Route price for '{val.PlanetName}' set to {Price} (now {extendedLevel.RoutePrice}).");
					}
				}
				if (!flag)
				{
					Plugin.Log.LogWarning((object)"RoutePriceOverride: 11 Apollo ExtendedLevel not found.");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("RoutePriceOverride: " + ex));
			}
		}
	}
	internal static class SuitsRegistration
	{
		private static readonly (string key, string name)[] Suits = new(string, string)[4]
		{
			("Moonwalker", "Moonwalker suit"),
			("Pumpkin", "Pumpkin suit"),
			("Sokol", "Sokol suit"),
			("ApolloA7L", "Apollo A7L suit")
		};

		internal static void Register(AssetBundle bundle, ConfigFile cfg)
		{
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Expected O, but got Unknown
			if (!cfg.Bind<bool>("Suits", "Enabled", true, "Add the space suits to the ship's suit rack.").Value)
			{
				return;
			}
			bool value = cfg.Bind<bool>("Suits", "SuitsAlwaysUnlocked", true, "true = suits hang on the rack from the start (free). false = buy them in the terminal store.").Value;
			int value2 = cfg.Bind<int>("Suits", "Price", 60, "Store price per suit when SuitsAlwaysUnlocked = false.").Value;
			List<string> source = (from s in cfg.Bind<string>("Suits", "EnabledSuits", "Moonwalker,Pumpkin,Sokol,ApolloA7L", "Comma-separated suits to add (Moonwalker, Pumpkin, Sokol, ApolloA7L).").Value.Split(',')
				select s.Trim() into s
				where s.Length > 0
				select s).ToList();
			int num = 0;
			(string, string)[] suits = Suits;
			for (int num2 = 0; num2 < suits.Length; num2++)
			{
				var (key, unlockableName) = suits[num2];
				if (!source.Any((string s) => s.Equals(key, StringComparison.OrdinalIgnoreCase)))
				{
					continue;
				}
				Material val = bundle.LoadAsset<Material>("Apollo11Suit_" + key);
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogError((object)("Suit material missing: Apollo11Suit_" + key));
					continue;
				}
				UnlockableItem val2 = new UnlockableItem
				{
					unlockableName = unlockableName,
					unlockableType = 0,
					suitMaterial = val,
					alreadyUnlocked = value,
					alwaysInStock = true,
					IsPlaceable = false,
					spawnPrefab = false,
					canBeStored = false,
					maxNumber = 1
				};
				if (value)
				{
					Unlockables.RegisterUnlockable(val2, (StoreType)0, (TerminalNode)null, (TerminalNode)null, (TerminalNode)null, -1);
				}
				else
				{
					Unlockables.RegisterUnlockable(val2, (StoreType)1, (TerminalNode)null, (TerminalNode)null, (TerminalNode)null, Math.Max(0, value2));
				}
				num++;
			}
			Plugin.Log.LogInfo((object)string.Format("Suits: {0} space suits registered ({1}).", num, value ? "always unlocked" : ("store, " + value2 + " credits")));
		}
	}
	[HarmonyPatch(typeof(RoundManager), "RefreshEnemyVents")]
	internal static class TestSpawner
	{
		internal static bool Enabled;

		internal static int Count = 3;

		internal static string Moons = "Experimentation";

		internal static EnemyType CrackType;

		private static string lastKey;

		[HarmonyPostfix]
		private static void Postfix(RoundManager __instance)
		{
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c2: 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_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: 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)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!Enabled || (Object)(object)CrackType == (Object)null || !((NetworkBehaviour)__instance).IsServer || !__instance.dungeonFinishedGeneratingForAllPlayers)
				{
					return;
				}
				SelectableLevel currentLevel = __instance.currentLevel;
				if ((Object)(object)currentLevel == (Object)null || !currentLevel.spawnEnemiesAndScrap)
				{
					return;
				}
				string text = currentLevel.levelID + ":" + StartOfRound.Instance.randomMapSeed;
				if (text == lastKey)
				{
					return;
				}
				lastKey = text;
				if (!MoonFeatures.MoonMatches(currentLevel, Moons))
				{
					Plugin.Log.LogInfo((object)("[TestSpawn] skipping, level '" + currentLevel.PlanetName + "' not in ForceSpawnMoons='" + Moons + "'."));
					return;
				}
				EntranceTeleport val = ((IEnumerable<EntranceTeleport>)Object.FindObjectsOfType<EntranceTeleport>()).FirstOrDefault((Func<EntranceTeleport, bool>)((EntranceTeleport e) => e.entranceId == 0 && !e.isEntranceToBuilding));
				Vector3 origin = (((Object)(object)val != (Object)null) ? val.entrancePoint.position : ((__instance.insideAINodes.Length != 0) ? __instance.insideAINodes[0].transform.position : Vector3.zero));
				Plugin.Log.LogInfo((object)($"[TestSpawn] level '{currentLevel.PlanetName}', main entrance (inside) at {origin} (found={(Object)(object)val != (Object)null}), " + $"insideAINodes={__instance.insideAINodes.Length}, spawning {Count} Wall Crack(s)."));
				List<GameObject> list = (from n in __instance.insideAINodes
					where (Object)(object)n != (Object)null
					orderby Vector3.Distance(n.transform.position, origin)
					select n).Take(Math.Max(Count * 3, 6)).ToList();
				if (list.Count == 0)
				{
					Plugin.Log.LogError((object)"[TestSpawn] no insideAINodes, cannot spawn.");
					return;
				}
				Random random = new Random(StartOfRound.Instance.randomMapSeed + 4711);
				for (int num = 0; num < Count; num++)
				{
					GameObject val2 = list[Math.Min(list.Count - 1, num * 3 + random.Next(0, 2))];
					Vector3 randomNavMeshPositionInRadius = __instance.GetRandomNavMeshPositionInRadius(val2.transform.position, 1.5f, default(NavMeshHit));
					try
					{
						__instance.SpawnEnemyGameObject(randomNavMeshPositionInRadius, (float)random.NextDouble() * 360f, -1, CrackType);
						Plugin.Log.LogInfo((object)$"[TestSpawn] #{num + 1} spawned at {randomNavMeshPositionInRadius} (node '{((Object)val2).name}', {Vector3.Distance(randomNavMeshPositionInRadius, origin):F1} m from main entrance).");
					}
					catch (Exception arg)
					{
						Plugin.Log.LogError((object)$"[TestSpawn] #{num + 1} spawn at {randomNavMeshPositionInRadius} failed: {arg}");
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[TestSpawn] failed: " + ex));
			}
		}
	}
	[HarmonyPatch(typeof(RoundManager), "RefreshEnemyVents")]
	internal static class TestSpawnerDeanie
	{
		private static string lastKey;

		[HarmonyPostfix]
		private static void Postfix(RoundManager __instance)
		{
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: 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_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				EnemyType type = DeanieRegistration.DeanieType;
				string testMoons = DeanieRegistration.TestMoons;
				if ((Object)(object)type == (Object)null || string.IsNullOrEmpty(testMoons) || !((NetworkBehaviour)__instance).IsServer || !__instance.dungeonFinishedGeneratingForAllPlayers)
				{
					return;
				}
				SelectableLevel currentLevel = __instance.currentLevel;
				if ((Object)(object)currentLevel == (Object)null || !currentLevel.spawnEnemiesAndScrap)
				{
					return;
				}
				string text = currentLevel.levelID + ":" + StartOfRound.Instance.randomMapSeed;
				if (text == lastKey)
				{
					return;
				}
				lastKey = text;
				if (!MoonFeatures.MoonMatches(currentLevel, testMoons))
				{
					Plugin.Log.LogInfo((object)("[DeanieTest] skipping, '" + currentLevel.PlanetName + "' not in TestMoons='" + testMoons + "'."));
					return;
				}
				if (Object.FindObjectsOfType<EnemyAI>().Any((EnemyAI e) => (Object)(object)e.enemyType == (Object)(object)type))
				{
					Plugin.Log.LogInfo((object)"[DeanieTest] a Deanie already exists, not spawning another.");
					return;
				}
				EntranceTeleport val = ((IEnumerable<EntranceTeleport>)Object.FindObjectsOfType<EntranceTeleport>()).FirstOrDefault((Func<EntranceTeleport, bool>)((EntranceTeleport e) => e.entranceId == 0 && !e.isEntranceToBuilding));
				Vector3 origin = (((Object)(object)val != (Object)null) ? val.entrancePoint.position : ((__instance.insideAINodes.Length != 0) ? __instance.insideAINodes[0].transform.position : Vector3.zero));
				GameObject val2 = (from n in __instance.insideAINodes
					where (Object)(object)n != (Object)null
					orderby Vector3.Distance(n.transform.position, origin)
					select n).Skip(1).FirstOrDefault();
				if ((Object)(object)val2 == (Object)null)
				{
					Plugin.Log.LogError((object)"[DeanieTest] no insideAINodes, cannot spawn.");
					return;
				}
				Vector3 randomNavMeshPositionInRadius = __instance.GetRandomNavMeshPositionInRadius(val2.transform.position, 1.5f, default(NavMeshHit));
				__instance.SpawnEnemyGameObject(randomNavMeshPositionInRadius, Random.Range(0f, 360f), -1, type);
				Plugin.Log.LogInfo((object)$"[DeanieTest] spawned 1 Deanie at {randomNavMeshPositionInRadius} (node '{((Object)val2).name}', {Vector3.Distance(randomNavMeshPositionInRadius, origin):F1} m from the main entrance) on '{currentLevel.PlanetName}'.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[DeanieTest] failed: " + ex));
			}
		}
	}
	[HarmonyPatch(typeof(RoundManager), "RefreshEnemyVents")]
	internal static class TestSpawnerDoppel
	{
		private static string lastKey;

		[HarmonyPostfix]
		private static void Postfix(RoundManager __instance)
		{
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: 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_0237: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				EnemyType type = DoppelRegistration.DoppelType;
				string testMoons = DoppelRegistration.TestMoons;
				if ((Object)(object)type == (Object)null || string.IsNullOrEmpty(testMoons) || !((NetworkBehaviour)__instance).IsServer || !__instance.dungeonFinishedGeneratingForAllPlayers)
				{
					return;
				}
				SelectableLevel currentLevel = __instance.currentLevel;
				if ((Object)(object)currentLevel == (Object)null || !currentLevel.spawnEnemiesAndScrap)
				{
					return;
				}
				string text = currentLevel.levelID + ":" + StartOfRound.Instance.randomMapSeed;
				if (text == lastKey)
				{
					return;
				}
				lastKey = text;
				if (!MoonFeatures.MoonMatches(currentLevel, testMoons))
				{
					Plugin.Log.LogInfo((object)("[DoppelTest] skipping, '" + currentLevel.PlanetName + "' not in TestMoons='" + testMoons + "'."));
					return;
				}
				if (Object.FindObjectsOfType<EnemyAI>().Any((EnemyAI e) => (Object)(object)e.enemyType == (Object)(object)type))
				{
					Plugin.Log.LogInfo((object)"[DoppelTest] a Doppel already exists.");
					return;
				}
				EntranceTeleport val = ((IEnumerable<EntranceTeleport>)Object.FindObjectsOfType<EntranceTeleport>()).FirstOrDefault((Func<EntranceTeleport, bool>)((EntranceTeleport e) => e.entranceId == 0 && !e.isEntranceToBuilding));
				Vector3 origin = (((Object)(object)val != (Object)null) ? val.entrancePoint.position : ((__instance.insideAINodes.Length != 0) ? __instance.insideAINodes[0].transform.position : Vector3.zero));
				GameObject val2 = (from n in __instance.insideAINodes
					where (Object)(object)n != (Object)null
					orderby Vector3.Distance(n.transform.position, origin)
					select n).Skip(2).FirstOrDefault();
				if ((Object)(object)val2 == (Object)null)
				{
					Plugin.Log.LogError((object)"[DoppelTest] no insideAINodes.");
					return;
				}
				Vector3 randomNavMeshPositionInRadius = __instance.GetRandomNavMeshPositionInRadius(val2.transform.position, 1.5f, default(NavMeshHit));
				__instance.SpawnEnemyGameObject(randomNavMeshPositionInRadius, Random.Range(0f, 360f), -1, type);
				Plugin.Log.LogInfo((object)$"[DoppelTest] spawned 1 Doppel at {randomNavMeshPositionInRadius} ({Vector3.Distance(randomNavMeshPositionInRadius, origin):F1} m from main entrance) on '{currentLevel.PlanetName}'.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[DoppelTest] failed: " + ex));
			}
		}
	}
	[HarmonyPatch]
	internal static class VanillaAssetHooks
	{
		private static bool applied;

		[HarmonyPatch(typeof(StartOfRound), "Start")]
		[HarmonyPostfix]
		private static void StartOfRoundStart()
		{
			if (!((Object)(object)Plugin.Bundle == (Object)null))
			{
				int num = 0;
				int num2 = 0;
				VanillaAssetRefs[] array = Plugin.Bundle.LoadAllAssets<VanillaAssetRefs>();
				foreach (VanillaAssetRefs vanillaAssetRefs in array)
				{
					num += vanillaAssetRefs.Apply();
					num2++;
				}
				Plugin.Log.LogInfo((object)string.Format("[Apollo11] VanillaAssetRefs applied from {0} manifest(s){1}, {2} missing; running totals ok={3} missing={4}", num2, applied ? " (re-applied)" : "", num, VanillaResolver.TotalOk, VanillaResolver.TotalFail));
				applied = true;
			}
		}
	}
	[Serializable]
	public class VRef
	{
		public string target = "";

		public string comp = "";

		public int compIndex;

		public string prop = "";

		public string src = "";

		public string srcPath = "";

		public string srcComp = "";

		public int srcCompIndex;

		public string srcProp = "";

		public string label = "";
	}
	[DefaultExecutionOrder(-30000)]
	public class VanillaRefs : MonoBehaviour
	{
		public VRef[] refs = new VRef[0];

		public VanillaAssetRefs[] assetManifests = new VanillaAssetRefs[0];

		[NonSerialized]
		public bool resolved;

		private void Awake()
		{
			if (assetManifests != null)
			{
				VanillaAssetRefs[] array = assetManifests;
				foreach (VanillaAssetRefs vanillaAssetRefs in array)
				{
					if ((Object)(object)vanillaAssetRefs != (Object)null)
					{
						vanillaAssetRefs.Apply();
					}
				}
			}
			Resolve();
		}

		private void OnEnable()
		{
			if (!resolved)
			{
				Resolve();
			}
		}

		public void Resolve()
		{
			if (resolved || refs == null)
			{
				return;
			}
			int num = 0;
			int num2 = 0;
			VRef[] array = refs;
			foreach (VRef vRef in array)
			{
				try
				{
					Transform val = VanillaResolver.FindPath(((Component)this).transform, vRef.target);
					if ((Object)(object)val == (Object)null)
					{
						num2++;
						VanillaResolver.Miss(((Object)this).name, vRef, "target path missing");
						continue;
					}
					object component = VanillaResolver.GetComponent(((Component)val).gameObject, vRef.comp, vRef.compIndex);
					if (component == null)
					{
						num2++;
						VanillaResolver.Miss(((Object)this).name, vRef, "target component missing");
						continue;
					}
					Object val2 = VanillaResolver.Lookup(vRef);
					if (val2 == (Object)null)
					{
						num2++;
						VanillaResolver.Miss(((Object)this).name, vRef, "source not found");
					}
					else if (PropAccess.Set(component, vRef.prop, val2))
					{
						num++;
					}
					else
					{
						num2++;
						VanillaResolver.Miss(((Object)this).name, vRef, "set failed");
					}
				}
				catch (Exception ex)
				{
					num2++;
					VanillaResolver.Miss(((Object)this).name, vRef, ex.GetType().Name + ": " + ex.Message);
				}
			}
			resolved = num2 == 0 || VanillaResolver.GameReady;
			VanillaResolver.Report(((Object)this).name, num, num2, refs.Length);
			if (num2 == 0)
			{
				PostResolve();
			}
		}

		private void PostResolve()
		{
			Animator[] componentsInChildren = ((Component)this).GetComponentsInChildren<Animator>(true);
			foreach (Animator val in componentsInChildren)
			{
				if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.runtimeAnimatorController) && !val.isInitialized && ((Behaviour)val).isActiveAndEnabled)
				{
					val.Rebind();
				}
			}
		}
	}
	public class VanillaAssetRefs : ScriptableObject
	{
		[Serializable]
		public class Entry
		{
			public Object target;

			public VRef r = new VRef();
		}

		public Entry[] entries = new Entry[0];

		public int Apply()
		{
			int num = 0;
			int num2 = 0;
			Entry[] array = entries;
			foreach (Entry entry in array)
			{
				if (entry == null || entry.target == (Object)null)
				{
					continue;
				}
				try
				{
					Object val = VanillaResolver.Lookup(entry.r);
					if (val != (Object)null && PropAccess.Set(entry.target, entry.r.prop, val))
					{
						num++;
						continue;
					}
					num2++;
					VanillaResolver.Miss(entry.target.name, entry.r, (val == (Object)null) ? "source not found" : "set failed");
				}
				catch (Exception ex)
				{
					num2++;
					VanillaResolver.Miss(entry.target.name, entry.r, ex.Message);
				}
			}
			VanillaResolver.Report("asset manifest " + ((Object)this).name, num, num2, entries.Length);
			return num2;
		}
	}
	public static class VanillaResolver
	{
		private static readonly Dictionary<string, Object> cache = new Dictionary<string, Object>();

		private static Dictionary<string, GameObject> prefabRoots;

		private static readonly Dictionary<Type, Dictionary<string, Object>> byType = new Dictionary<Type, Dictionary<string, Object>>();

		private static readonly HashSet<string> reported = new HashSet<string>();

		private static bool hooked;

		public static int TotalOk;

		public static int TotalFail;

		private static readonly Dictionary<string, Type> types = new Dictionary<string, Type>();

		public static bool GameReady => (Object)(object)StartOfRound.Instance != (Object)null;

		public static Transform FindPath(Transform root, string path)
		{
			if (string.IsNullOrEmpty(path))
			{
				return root;
			}
			Transform val = root;
			string[] array = path.Split('/');
			foreach (string text in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					return null;
				}
				int num = text.LastIndexOf('#');
				if (num > 0 && int.TryParse(text.Substring(num + 1), out var result))
				{
					Transform val2 = ((result < val.childCount) ? val.GetChild(result) : null);
					val = (((Object)(object)val2 != (Object)null && ((Object)val2).name == text.Substring(0, num)) ? val2 : null);
				}
				else
				{
					val = val.Find(text);
				}
			}
			return val;
		}

		private static void Hook()
		{
			if (!hooked)
			{
				hooked = true;
				SceneManager.sceneLoaded += delegate
				{
					Flush();
				};
			}
		}

		public static void Flush()
		{
			cache.Clear();
			prefabRoots = null;
			byType.Clear();
		}

		internal static void Miss(string owner, VRef r, string why)
		{
			string item = owner + "|" + r.target + "|" + r.prop + "|" + why;
			if (reported.Add(item))
			{
				Debug.LogWarning((object)("[Apollo11] VanillaRefs MISS on '" + owner + "' " + r.target + " " + r.comp + "." + r.prop + " <- " + r.src + " " + r.srcPath + " " + r.srcComp + "." + r.srcProp + " ('" + r.label + "'): " + why));
			}
		}

		internal static void Report(string owner, int ok, int fail, int total)
		{
			TotalOk += ok;
			TotalFail += fail;
			if (reported.Add("R|" + owner + "|" + fail))
			{
				Debug.Log((object)string.Format("[Apollo11] VanillaRefs '{0}': {1}/{2} vanilla refs resolved from the game{3}", owner, ok, total, (fail > 0) ? (", " + fail + " MISSING") : ""));
			}
		}

		public static object GetComponent(GameObject go, string type, int index)
		{
			if (string.IsNullOrEmpty(type))
			{
				return go;
			}
			int num = 0;
			Component[] components = go.GetComponents<Component>();
			foreach (Component val in components)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Type type2 = ((object)val).GetType();
				if (type2.FullName == type || type2.Name == type)
				{
					if (num == index)
					{
						return val;
					}
					num++;
				}
			}
			return null;
		}

		public static Object Lookup(VRef r)
		{
			Hook();
			string key = r.src + "|" + r.srcPath + "|" + r.srcComp + "|" + r.srcCompIndex + "|" + r.srcProp;
			if (cache.TryGetValue(key, out var value) && value != (Object)null)
			{
				return value;
			}
			Object val = LookupUncached(r);
			if (val != (Object)null)
			{
				cache[key] = val;
			}
			return val;
		}

		private static Object LookupUncached(VRef r)
		{
			string text = r.src ?? "";
			int num = text.IndexOf(':');
			string text2 = ((num < 0) ? text : text.Substring(0, num));
			string arg = ((num < 0) ? "" : text.Substring(num + 1));
			object obj = null;
			switch (text2)
			{
			case "asset":
			{
				int num2 = arg.IndexOf(':');
				Type type2 = FindType(arg.Substring(0, num2));
				string n = arg.Substring(num2 + 1);
				if (type2 == null)
				{
					return null;
				}
				obj = ByName(type2, n);
				break;
			}
			case "mixer":
			{
				string[] parts = arg.Split('/');
				return (Object)(object)((IEnumerable<AudioMixerGroup>)Resources.FindObjectsOfTypeAll<AudioMixerGroup>()).FirstOrDefault((Func<AudioMixerGroup, bool>)((AudioMixerGroup g) => Object.op_Implicit((Object)(object)g) && ((Object)g).name == parts[1] && Object.op_Implicit((Object)(object)g.audioMixer) && ((Object)g.audioMixer).name == parts[0]));
			}
			case "go":
				obj = PrefabRoot(arg);
				break;
			case "single":
			{
				Type type = FindType(arg);
				obj = ((type != null) ? Object.FindObjectOfType(type) : null);
				break;
			}
			case "item":
				obj = FindItem(arg)?.spawnPrefab;
				break;
			case "itemSO":
				obj = FindItem(arg);
				break;
			case "player":
				obj = (((Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.allPlayerScripts != null && StartOfRound.Instance.allPlayerScripts.Length != 0) ? ((Component)StartOfRound.Instance.allPlayerScripts[0]).gameObject : null);
				break;
			case "level":
				obj = StartOfRound.Instance?.levels?.FirstOrDefault((Func<SelectableLevel, bool>)((SelectableLevel l) => Object.op_Implicit((Object)(object)l) && ((Object)l).name == arg))?.planetPrefab ?? ((IEnumerable<SelectableLevel>)Resources.FindObjectsOfTypeAll<SelectableLevel>()).FirstOrDefault((Func<SelectableLevel, bool>)((SelectableLevel l) => Object.op_Implicit((Object)(object)l) && ((Object)l).name == arg))?.planetPrefab;
				break;
			}
			if (obj == null)
			{
				return null;
			}
			object obj2 = obj;
			GameObject val = (GameObject)((obj is GameObject) ? obj : null);
			if (val != null)
			{
				Transform val2 = FindPath(val.transform, r.srcPath);
				if ((Object)(object)val2 == (Object)null)
				{
					return null;
				}
				obj2 = GetComponent(((Component)val2).gameObject, r.srcComp, r.srcCompIndex);
			}
			if (obj2 == null)
			{
				return null;
			}
			if (string.IsNullOrEmpty(r.srcProp))
			{
				return (Object)((obj2 is Object) ? obj2 : null);
			}
			object obj3 = PropAccess.Get(obj2, r.srcProp);
			return (Object)((obj3 is Object) ? obj3 : null);
		}

		private static Item FindItem(string n)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			return (Item)(((object)(StartOfRound.Instance?.allItemsList?.itemsList)?.FirstOrDefault((Func<Item, bool>)((Item i) => Object.op_Implicit((Object)(object)i) && ((Object)i).name == n))) ?? ((object)(Item)ByName(typeof(Item), n)));
		}

		private static Object ByName(Type t, string n)
		{
			//IL_004c: 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)
			if (!byType.TryGetValue(t, out var value))
			{
				value = new Dictionary<string, Object>();
				Object[] array = Resources.FindObjectsOfTypeAll(t);
				foreach (Object val in array)
				{
					if (!Object.op_Implicit(val) || value.ContainsKey(val.name))
					{
						continue;
					}
					GameObject val2 = (GameObject)(object)((val is GameObject) ? val : null);
					if (val2 != null)
					{
						Scene scene = val2.scene;
						if (((Scene)(ref scene)).IsValid())
						{
							continue;
						}
					}
					if (!(val is Component))
					{
						value[val.name] = val;
					}
				}
				byType[t] = value;
			}
			if (!value.TryGetValue(n, out var value2))
			{
				return null;
			}
			return value2;
		}

		private static GameObject PrefabRoot(string n)
		{
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton != (Object)null)
			{
				NetworkConfig networkConfig = singleton.NetworkConfig;
				object obj;
				if (networkConfig == null)
				{
					obj = null;
				}
				else
				{
					NetworkPrefabs prefabs = networkConfig.Prefabs;
					obj = ((prefabs != null) ? prefabs.Prefabs : null);
				}
				if (obj != null)
				{
					foreach (NetworkPrefab prefab in singleton.NetworkConfig.Prefabs.Prefabs)
					{
						if ((Object)(object)prefab?.Prefab != (Object)null && ((Object)prefab.Prefab).name == n)
						{
							return prefab.Prefab;
						}
					}
				}
			}
			if (prefabRoots == null)
			{
				prefabRoots = new Dictionary<string, GameObject>();
				GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>();
				foreach (GameObject val in array)
				{
					if (Object.op_Implicit((Object)(object)val) && (Object)(object)val.transform.parent == (Object)null)
					{
						Scene scene = val.scene;
						if (!((Scene)(ref scene)).IsValid() && !prefabRoots.ContainsKey(((Object)val).name))
						{
							prefabRoots[((Object)val).name] = val;
						}
					}
				}
			}
			if (!prefabRoots.TryGetValue(n, out var value))
			{
				return null;
			}
			return value;
		}

		public static Type FindType(string full)
		{
			if (types.TryGetValue(full, out var value))
			{
				return value;
			}
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					value = assembly.GetType(full, throwOnError: false);
				}
				catch
				{
					value = null;
				}
				if (value != null)
				{
					break;
				}
			}
			types[full] = value;
			return value;
		}
	}
	public static class PropAccess
	{
		private const BindingFlags F = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static (string head, int index, string rest) Split(string path)
		{
			int num = path.IndexOf('.');
			string item = ((num < 0) ? path : path.Substring(0, num));
			string text = ((num < 0) ? "" : path.Substring(num + 1));
			int item2 = -1;
			if (text.StartsWith("Array.data["))
			{
				int num2 = text.IndexOf(']');
				item2 = int.Parse(text.Substring(11, num2 - 11));
				text = ((text.Length > num2 + 2) ? text.Substring(num2 + 2) : "");
			}
			return (head: item, index: item2, rest: text);
		}

		public static object Get(object owner, string path)
		{
			if (owner == null)
			{
				return null;
			}
			if (path.StartsWith("tex:"))
			{
				object obj = ((owner is Material) ? owner : null);
				if (obj == null)
				{
					return null;
				}
				return ((Material)obj).GetTexture(path.Substring(4));
			}
			var (text, num, text2) = Split(path);
			if (TryBuiltinGet(owner, text, num, out var v))
			{
				return v;
			}
			object obj2 = GetMember(owner, text);
			if (num >= 0)
			{
				obj2 = ((obj2 is IList list && num < list.Count) ? list[num] : null);
			}
			if (text2.Length <= 0)
			{
				return obj2;
			}
			return Get(obj2, text2);
		}

		public static bool Set(object owner, string path, object value)
		{
			if (owner == null)
			{
				return false;
			}
			if (path.StartsWith("tex:"))
			{
				Material val = (Material)((owner is Material) ? owner : null);
				if (!Object.op_Implicit((Object)(object)val))
				{
					return false;
				}
				val.SetTexture(path.Substring(4), (Texture)((value is Texture) ? value : null));
				return true;
			}
			var (text, num, text2) = Split(path);
			if (TrySpecialSet(owner, text, num, value, out var ok))
			{
				return ok;
			}
			if (text2.Length == 0)
			{
				if (num < 0)
				{
					return SetMember(owner, text, value);
				}
				if (!(GetMember(owner, text) is IList list) || num >= list.Count)
				{
					return false;
				}
				list[num] = value;
				return true;
			}
			object member = GetMember(owner, text);
			if (num >= 0)
			{
				if (!(member is IList list2) || num >= list2.Count)
				{
					return false;
				}
				object obj = list2[num];
				if (!Set(obj, text2, value))
				{
					return false;
				}
				list2[num] = obj;
				return true;
			}
			if (member == null)
			{
				return false;
			}
			if (!Set(member, text2, value))
			{
				return false;
			}
			if (member.GetType().IsValueType)
			{
				SetMember(owner, text, member);
			}
			return true;
		}

		private static bool TryBuiltinGet(object o, string head, int idx, out object v)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			v = null;
			MeshFilter val = (MeshFilter)((o is MeshFilter) ? o : null);
			Renderer val3;
			int num;
			if (val == null)
			{
				SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)((o is SkinnedMeshRenderer) ? o : null);
				if (val2 != null)
				{
					if (!(head == "m_Mesh"))
					{
						val3 = (Renderer)o;
						num = 2;
						goto IL_0100;
					}
					v = val2.sharedMesh;
					return true;
				}
				MeshCollider val4 = (MeshCollider)((o is MeshCollider) ? o : null);
				if (val4 == null)
				{
					val3 = (Renderer)((o is Renderer) ? o : null);
					if (val3 != null)
					{
						num = 4;
						goto IL_0100;
					}
					AudioSource val5 = (AudioSource)((o is AudioSource) ? o : null);
					if (val5 == null)
					{
						Animator val6 = (Animator)((o is Animator) ? o : null);
						if (val6 == null)
						{
							Light val7 = (Light)((o is Light) ? o : null);
							if (val7 != null && head == "m_Cookie")
							{
								v = val7.cookie;
								return true;
							}
						}
						else
						{
							if (head == "m_Controller")
							{
								v = val6.runtimeAnimatorController;
								return true;
							}
							Animator val8 = val6;
							if (head == "m_Avatar")
							{
								v = val8.avatar;
								return true;
							}
						}
					}
					else
					{
						if (head == "m_audioClip")
						{
							v = val5.clip;
							return true;
						}
						AudioSource val9 = val5;
						if (head == "OutputAudioMixerGroup")
						{
							v = val9.outputAudioMixerGroup;
							return true;
						}
					}
				}
				else if (head == "m_Mesh")
				{
					v = val4.sharedMesh;
					return true;
				}
			}
			else if (head == "m_Mesh")
			{
				v = val.sharedMesh;
				return true;
			}
			goto IL_01ed;
			IL_0100:
			if (head == "m_Materials")
			{
				goto IL_011b;
			}
			if (num != 2)
			{
				if (num != 4)
				{
					goto IL_011b;
				}
				SpriteRenderer val10 = (SpriteRenderer)((o is SpriteRenderer) ? o : null);
				if (val10 == null)
				{
					ParticleSystemRenderer val11 = (ParticleSystemRenderer)((o is ParticleSystemRenderer) ? o : null);
					if (val11 != null && head == "m_Mesh")
					{
						v = val11.mesh;
						return true;
					}
				}
				else if (head == "m_Sprite")
				{
					v = val10.sprite;
					return true;
				}
			}
			goto IL_01ed;
			IL_01ed:
			if (head.StartsWith("m_") && o is Component)
			{
				foreach (string item in Aliases(head))
				{
					PropertyInfo property = o.GetType().GetProperty(item, BindingFlags.Instance | BindingFlags.Public);
					if (property != null && property.CanRead)
					{
						v = property.GetValue(o);
						if (idx >= 0)
						{
							v = ((v is IList list && idx < list.Count) ? list[idx] : null);
						}
						return true;
					}
				}
			}
			return false;
			IL_011b:
			Material[] sharedMaterials = val3.sharedMaterials;
			v = ((idx >= 0 && idx < sharedMaterials.Length) ? sharedMaterials[idx] : null);
			return true;
		}

		private static bool TrySpecialSet(object o, string head, int idx, object value, out bool ok)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			ok = true;
			MeshFilter val = (MeshFilter)((o is MeshFilter) ? o : null);
			Renderer val3;
			int num;
			if (val == null)
			{
				SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)((o is SkinnedMeshRenderer) ? o : null);
				if (val2 != null)
				{
					if (!(head == "m_Mesh"))
					{
						val3 = (Renderer)o;
						num = 2;
						goto IL_010d;
					}
					val2.sharedMesh = (Mesh)((value is Mesh) ? value : null);
					return true;
				}
				MeshCollider val4 = (MeshCollider)((o is MeshCollider) ? o : null);
				if (val4 == null)
				{
					val3 = (Renderer)((o is Renderer) ? o : null);
					if (val3 != null)
					{
						num = 4;
						goto IL_010d;
					}
					AudioSource val5 = (AudioSource)((o is AudioSource) ? o : null);
					if (val5 == null)
					{
						Animator val6 = (Animator)((o is Animator) ? o : null);
						if (val6 == null)
						{
							Light val7 = (Light)((o is Light) ? o : null);
							if (val7 != null && head == "m_Cookie")
							{
								val7.cookie = (Texture)((value is Texture) ? value : null);
								return true;
							}
						}
						else
						{
							if (head == "m_Controller")
							{
								val6.runtimeAnimatorController = (RuntimeAnimatorController)((value is RuntimeAnimatorController) ? value : null);
								return true;
							}
							Animator val8 = val6;
							if (head == "m_Avatar")
							{
								val8.avatar = (Avatar)((value is Avatar) ? value : null);
								return true;
							}
						}
					}
					else
					{
						if (head == "m_audioClip")
						{
							val5.clip = (AudioClip)((value is AudioClip) ? value : null);
							return true;
						}
						AudioSource val9 = val5;
						if (head == "OutputAudioMixerGroup")
						{
							val9.outputAudioMixerGroup = (AudioMixerGroup)((value is AudioMixerGroup) ? value : null);
							return true;
						}
					}
				}
				else if (head == "m_Mesh")
				{
					val4.sharedMesh = (Mesh)((value is Mesh) ? value : null);
					return true;
				}
			}
			else if (head == "m_Mesh")
			{
				val.sharedMesh = (Mesh)((value is Mesh) ? value : null);
				return true;
			}
			goto IL_0229;
			IL_0128:
			Material[] sharedMaterials = val3.sharedMaterials;
			if (idx < 0 || idx >= sharedMaterials.Length)
			{
				ok = false;
				return true;
			}
			sharedMaterials[idx] = (Material)((value is Material) ? value : null);
			val3.sharedMaterials = sharedMaterials;
			return true;
			IL_0229:
			if (head.StartsWith("m_") && o is Component)
			{
				foreach (string item in Aliases(head))
				{
					PropertyInfo property = o.GetType().GetProperty(item, BindingFlags.Instance | BindingFlags.Public);
					if (property != null && property.CanWrite && idx < 0)
					{
						property.SetValue(o, value);
						return true;
					}
				}
			}
			ok = false;
			return false;
			IL_010d:
			if (head == "m_Materials")
			{
				goto IL_0128;
			}
			if (num != 2)
			{
				if (num != 4)
				{
					goto IL_0128;
				}
				SpriteRenderer val10 = (SpriteRenderer)((o is SpriteRenderer) ? o : null);
				if (val10 == null)
				{
					ParticleSystemRenderer val11 = (ParticleSystemRenderer)((o is ParticleSystemRenderer) ? o : null);
					if (val11 != null && head == "m_Mesh")
					{
						val11.mesh = (Mesh)((value is Mesh) ? value : null);
						return true;
					}
				}
				else if (head == "m_Sprite")
				{
					val10.sprite = (Sprite)((value is Sprite) ? value : null);
					return true;
				}
			}
			goto IL_0229;
		}

		private static IEnumerable<string> Aliases(string head)
		{
			string b = head.Substring(2);
			string lc = char.ToLowerInvariant(b[0]) + b.Substring(1);
			if (!(head == "m_fontAsset"))
			{
				if (head == "m_sharedMaterial")
				{
					yield return "fontSharedMaterial";
					yield return "sharedMaterial";
				}
			}
			else
			{
				yield return "font";
			}
			yield return "shared" + b;
			yield return lc;
			yield return b;
		}

		private static object GetMember(object o, string n)
		{
			Type type = o.GetType();
			while (type != null)
			{
				FieldInfo field = type.GetField(n, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					return field.GetValue(o);
				}
				type = type.BaseType;
			}
			PropertyInfo property = o.GetType().GetProperty(n, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (!(property != null) || !property.CanRead)
			{
				return null;
			}
			return property.GetValue(o);
		}

		private static bool SetMember(object o, string n, object v)
		{
			Type type = o.GetType();
			while (type != null)
			{
				FieldInfo field = type.GetField(n, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					field.SetValue(o, v);
					return true;
				}
				type = type.BaseType;
			}
			PropertyInfo property = o.GetType().GetProperty(n, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null && property.CanWrite)
			{
				property.SetValue(o, v);
				return true;
			}
			return false;
		}
	}
	internal static class ZombieRegistration
	{
		internal static EnemyType ZombieType;

		internal static int Rarity = 20;

		internal static int VanillaRarity = 0;

		internal static int TestRarity = 1000;

		internal static int TestCount = 1;

		internal static string VanillaMoons = "";

		internal static string TestMoons = "";

		private static string lastKey;

		internal static void Register(AssetBundle bundle, ConfigFile cfg)
		{
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			EnemyType val = bundle.LoadAsset<EnemyType>("ZombieEnemy");
			TerminalNode val2 = bundle.LoadAsset<TerminalNode>("ZombieTN");
			TerminalKeyword val3 = bundle.LoadAsset<TerminalKeyword>("ZombieTK");
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"ZombieEnemy not in bundle (build with Apollo11BuildZombie) - Zombie disabled.");
				return;
			}
			NetworkPrefabs.RegisterNetworkPrefab(val.enemyPrefab);
			if (cfg.Bind<bool>("Zombie", "Enabled", true, "Add the Zombie (dead crewmate, arms out, slow, turns its victims).").Value)
			{
				Rarity = cfg.Bind<int>("Zombie", "Rarity", 20, "Spawn weight inside the Lunar Base on 11 Apollo.").Value;
				VanillaRarity = cfg.Bind<int>("Zombie", "VanillaRarity", 0, "Indoor spawn weight on the moons in VanillaMoons (0 = Apollo only).").Value;
				VanillaMoons = cfg.Bind<string>("Zombie", "VanillaMoons", "Experimentation,Assurance,Vow,Offense,March,Adamance,Rend,Dine,Titan,Artifice,Embrion", "Planet-name fragments (comma separated) or All, used when VanillaRarity > 0.").Value;
				val.MaxCount = cfg.Bind<int>("Zombie", "MaxCount", 3, "Max naturally spawned Zombies at once (risen victims don't use this cap).").Value;
				ZombieSettings.MaxTotal = cfg.Bind<int>("Zombie", "MaxTotal", 8, "Victims stop rising once this many Zombies are alive.").Value;
				ZombieSettings.SpawnFromKills = cfg.Bind<bool>("Zombie", "SpawnFromKills", true, "A player killed by a Zombie rises as a new Zombie in their suit.").Value;
				ZombieSettings.Speed = cfg.Bind<float>("Zombie", "Speed", 2.2f, "Walk speed (player walk is ~4.6).").Value;
				ZombieSettings.MaxHP = Math.Max(1, cfg.Bind<int>("Zombie", "HP", 4, "Health (shovel hit = 1, like the Masked).").Value);
				ZombieSettings.KillDuration = cfg.Bind<float>("Zombie", "KillDuration", 2.2f, "Seconds from grab to death.").Value;
				ZombieSettings.GroanIntervalMin = cfg.Bind<float>("Zombie", "GroanIntervalMin", 4f, "Min seconds between groans.").Value;
				ZombieSettings.GroanIntervalMax = cfg.Bind<float>("Zombie", "GroanIntervalMax", 9f, "Max seconds between groans.").Value;
				ZombieSettings.GroanVolume = cfg.Bind<float>("Zombie", "GroanVolume", 1f, "Groan volume.").Value;
				ZombieSettings.PaleTint = cfg.Bind<bool>("Zombie", "PaleTint", true, "Grey-green dead tint over the suit.").Value;
				bool value = cfg.Bind<bool>("Zombie", "TestForceSpawn", false, "TESTING: huge spawn weight + host spawns TestCount Zombies near the main entrance on TestMoons.").Value;
				TestRarity = cfg.Bind<int>("Zombie", "TestRarity", 1000, "Weight when TestForceSpawn is true.").Value;
				TestCount = cfg.Bind<int>("Zombie", "TestCount", 1, "Zombies spawned near the main entrance when TestForceSpawn is true.").Value;
				TestMoons = (value ? cfg.Bind<string>("Zombie", "TestMoons", "Apollo", "Planet-name fragments or All.").Value : "");
				if (value)
				{
					val.probabilityCurve = AnimationCurve.Constant(0f, 1f, 1f);
				}
				((EnemyAI)val.enemyPrefab.GetComponent<ZombieAI>()).enemyHP = ZombieSettings.MaxHP;
				Enemies.RegisterEnemy(val, Rarity, (LevelTypes)1, val2, val3);
				ZombieType = val;
				new Harmony("rfgames.apollo11mod.zombie").PatchAll(typeof(ZombieRegistration));
				Plugin.Log.LogInfo((object)string.Format("Zombie registered (Apollo rarity {0}, vanilla {1}, max {2}{3}).", Rarity, VanillaRarity, val.MaxCount, value ? $", TEST weight {TestRarity} on '{TestMoons}'" : ""));
			}
		}

		[HarmonyPatch(typeof(RoundManager), "LoadNewLevel")]
		[HarmonyPrefix]
		private static void Inject(SelectableLevel newLevel)
		{
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			try
			{
				if ((Object)(object)ZombieType == (Object)null || (Object)(object)newLevel == (Object)null)
				{
					return;
				}
				int num = (MoonFeatures.MoonMatches(newLevel, TestMoons) ? TestRarity : (MoonFeatures.IsApollo(newLevel) ? Rarity : ((VanillaRarity > 0 && MoonFeatures.MoonMatches(newLevel, VanillaMoons)) ? VanillaRarity : 0)));
				SpawnableEnemyWithRarity val = ((IEnumerable<SpawnableEnemyWithRarity>)newLevel.Enemies).FirstOrDefault((Func<SpawnableEnemyWithRarity, bool>)((SpawnableEnemyWithRarity e) => e != null && (Object)(object)e.enemyType == (Object)(object)ZombieType));
				if (num <= 0)
				{
					if (val != null)
					{
						newLevel.Enemies.Remove(val);
					}
					return;
				}
				if (val == null)
				{
					val = new SpawnableEnemyWithRarity(ZombieType, num);
					newLevel.Enemies.Add(val);
				}
				val.rarity = num;
				Plugin.Log.LogInfo((object)$"Zombie weight {num} on '{newLevel.PlanetName}'.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Zombie Inject: " + ex));
			}
		}

		[HarmonyPatch(typeof(RoundManager), "RefreshEnemyVents")]
		[HarmonyPostfix]
		private static void TestSpawn(RoundManager __instance)
		{
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: 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_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: 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_01bc: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)ZombieType == (Object)null || string.IsNullOrEmpty(TestMoons) || !((NetworkBehaviour)__instance).IsServer || !__instance.dungeonFinishedGeneratingForAllPlayers)
				{
					return;
				}
				SelectableLevel currentLevel = __instance.currentLevel;
				if ((Object)(object)currentLevel == (Object)null || !currentLevel.spawnEnemiesAndScrap || !MoonFeatures.MoonMatches(currentLevel, TestMoons))
				{
					return;
				}
				string text = currentLevel.levelID + ":" + StartOfRound.Instance.randomMapSeed;
				if (!(text == lastKey))
				{
					lastKey = text;
					EntranceTeleport val = ((IEnumerable<EntranceTeleport>)Object.FindObjectsOfType<EntranceTeleport>()).FirstOrDefault((Func<EntranceTeleport, bool>)((EntranceTeleport e) => e.entranceId == 0 && !e.isEntranceToBuilding));
					Vector3 origin = (((Object)(object)val != (Object)null) ? val.entrancePoint.position : ((__instance.insideAINodes.Length != 0) ? __instance.insideAINodes[0].transform.position : Vector3.zero));
					GameObject[] array = (from n in __instance.insideAINodes
						where (Object)(object)n != (Object)null
						orderby Vector3.Distance(n.transform.position, origin)
						select n).Skip(3).Take(Math.Max(1, TestCount)).ToArray();
					foreach (GameObject val2 in array)
					{
						Vector3 randomNavMeshPositionInRadius = __instance.GetRandomNavMeshPositionInRadius(val2.transform.position, 1.5f, default(NavMeshHit));
						__instance.SpawnEnemyGameObject(randomNavMeshPositionInRadius, Random.Range(0f, 360f), -1, ZombieType);
						Plugin.Log.LogInfo((object)$"[ZombieTest] spawned Zombie at {randomNavMeshPositionInRadius} ({Vector3.Distance(randomNavMeshPositionInRadius, origin):F1} m from main entrance).");
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[ZombieTest] failed: " + ex));
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "rfgames.apollo11mod";

		public const string PLUGIN_NAME = "Apollo 11";

		public const string PLUGIN_VERSION = "1.0.4";
	}
}
namespace Apollo11Mod.Moon
{
	public class CraterHazard : MonoBehaviour
	{
		public Vector3 centre;

		public float innerR = 13f;

		public float outerR = 37f;

		public float killY;

		public float rimY;

		private float cooldown;

		private void Start()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			Debug.Log((object)$"[Apollo11] CraterHazard ring r {innerR}-{outerR} around {centre}, kill below y={killY:F1} (rim ~{rimY:F1})");
		}

		private void OnTriggerEnter(Collider other)
		{
			Check(other);
		}

		private void OnTriggerStay(Collider other)
		{
			Check(other);
		}

		private void Check(Collider other)
		{
			PlayerControllerB val = (Object.op_Implicit((Object)(object)other) ? ((Component)other).GetComponentInParent<PlayerControllerB>() : null);
			if ((Object)(object)val != (Object)null && IsLocal(val))
			{
				Kill(val, "trigger");
			}
		}

		private static bool IsLocal(PlayerControllerB p)
		{
			if ((Object)(object)GameNetworkManager.Instance != (Object)null)
			{
				return (Object)(object)p == (Object)(object)GameNetworkManager.Instance.localPlayerController;
			}
			return false;
		}

		private void Update()
		{
			//IL_006b: Unknown result type (might be d