Decompiled source of Grenade Launcher v2.0.1

BepInEx\plugins\DocValentyne-GrenadeLauncher\GrenadeLauncher.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PluginConfig.API;
using PluginConfig.API.Decorators;
using PluginConfig.API.Fields;
using PluginConfig.API.Functionals;
using Sandbox.Arm;
using ULTRAKILL.Cheats;
using ULTRAKILL.Enemy;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[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("GrenadeLauncher")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.0.1.0")]
[assembly: AssemblyInformationalVersion("2.0.1+3b87a19006529226179cb616ee205c962c6b369c")]
[assembly: AssemblyProduct("GrenadeLauncher")]
[assembly: AssemblyTitle("GrenadeLauncher")]
[assembly: AssemblyVersion("2.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace GrenadeLauncherMod
{
	[BepInPlugin("docvalentyne.ultrakill.grenadelauncher", "Grenade Launcher", "2.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "docvalentyne.ultrakill.grenadelauncher";

		public const string Name = "Grenade Launcher";

		public const string Version = "2.0.1";

		private GrenadeLauncherState state;

		private Harmony harmony;

		private GameObject runtimeHost;

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource LogSource { get; private set; }

		internal GrenadeLauncherState State => state;

		internal bool AnyGrenadeModeEnabled
		{
			get
			{
				int slot = Math.Max(0, GameProgressSaver.currentSlot);
				SlotLoadoutState slotState = GetSlotState(slot);
				if (!slotState.Migrated)
				{
					return slotState.LegacyEnabled;
				}
				if (!slotState.GetVariant(0) && !slotState.GetVariant(1))
				{
					return slotState.GetVariant(2);
				}
				return true;
			}
		}

		internal bool IsGrenadeModeEnabled(int variation)
		{
			if (variation < 0 || variation > 2)
			{
				return false;
			}
			int slot = Math.Max(0, GameProgressSaver.currentSlot);
			SlotLoadoutState slotState = GetSlotState(slot);
			if (!slotState.Migrated)
			{
				return slotState.LegacyEnabled;
			}
			return slotState.GetVariant(variation);
		}

		internal bool IsGrenadeModeEnabled(RocketLauncher launcher)
		{
			if ((Object)(object)launcher != (Object)null)
			{
				return IsGrenadeModeEnabled(launcher.variation);
			}
			return false;
		}

		internal void SetGrenadeModeEnabled(int variation, bool enabled)
		{
			if (variation >= 0 && variation <= 2)
			{
				int slot = Math.Max(0, GameProgressSaver.currentSlot);
				EnsureVariantMigration();
				GetSlotState(slot).SetVariant(variation, enabled);
				state.Save();
			}
		}

		internal void EnsureVariantMigration()
		{
			int slot = Math.Max(0, GameProgressSaver.currentSlot);
			SlotLoadoutState slotState = GetSlotState(slot);
			if (!slotState.Migrated)
			{
				bool legacyEnabled = slotState.LegacyEnabled;
				for (int i = 0; i < 3; i++)
				{
					slotState.SetVariant(i, legacyEnabled);
				}
				slotState.Migrated = true;
				state.Save();
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Migrated the old all-rocket loadout to per-variant Grenade Launcher choices for save slot " + slot + "."));
			}
		}

		private void Awake()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			Instance = this;
			LogSource = ((BaseUnityPlugin)this).Logger;
			state = GrenadeLauncherState.Load(((BaseUnityPlugin)this).Config.ConfigFilePath);
			PluginSettings.Initialize();
			harmony = new Harmony("docvalentyne.ultrakill.grenadelauncher");
			harmony.PatchAll(typeof(Plugin).Assembly);
			runtimeHost = new GameObject("Grenade Launcher Runtime");
			Object.DontDestroyOnLoad((Object)(object)runtimeHost);
			((Object)runtimeHost).hideFlags = (HideFlags)61;
			runtimeHost.AddComponent<TerminalIntegration>();
			runtimeHost.AddComponent<AlternateFireRuntime>();
			runtimeHost.AddComponent<WeaponVisualRuntime>();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Grenade Launcher v2.0.1 loaded.");
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			GrenadeSpawnContext.Reset();
			GrenadeLauncherHookContext.Reset();
			AlternateFireRuntime.CleanupAll();
			TerminalIntegration.Cleanup();
			if ((Object)(object)runtimeHost != (Object)null)
			{
				Object.Destroy((Object)(object)runtimeHost);
			}
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
			if (LogSource == ((BaseUnityPlugin)this).Logger)
			{
				LogSource = null;
			}
		}

		private SlotLoadoutState GetSlotState(int slot)
		{
			return state.GetSlot(Math.Max(0, slot));
		}
	}
	[Serializable]
	internal sealed class SlotLoadoutState
	{
		public int Slot;

		public bool LegacyEnabled;

		public bool Migrated;

		public bool Blue;

		public bool Green;

		public bool Red;

		internal bool GetVariant(int variation)
		{
			return variation switch
			{
				1 => Green, 
				0 => Blue, 
				_ => Red, 
			};
		}

		internal void SetVariant(int variation, bool value)
		{
			switch (variation)
			{
			case 0:
				Blue = value;
				break;
			case 1:
				Green = value;
				break;
			case 2:
				Red = value;
				break;
			}
		}
	}
	[Serializable]
	internal sealed class GrenadeLauncherState
	{
		public int BalanceDefaultsVersion;

		public int VisualCalibrationDefaultsVersion;

		public List<SlotLoadoutState> Slots = new List<SlotLoadoutState>();

		[NonSerialized]
		private string statePath;

		internal static GrenadeLauncherState Load(string oldConfigPath)
		{
			string path = Path.Combine(Path.GetDirectoryName(oldConfigPath) ?? Paths.ConfigPath, "docvalentyne.ultrakill.grenadelauncher.state.json");
			GrenadeLauncherState grenadeLauncherState = null;
			try
			{
				if (File.Exists(path))
				{
					grenadeLauncherState = JsonUtility.FromJson<GrenadeLauncherState>(File.ReadAllText(path));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logSource = Plugin.LogSource;
				if (logSource != null)
				{
					logSource.LogWarning((object)("Could not read Grenade Launcher internal state: " + ex.Message));
				}
			}
			if (grenadeLauncherState == null)
			{
				grenadeLauncherState = new GrenadeLauncherState();
				grenadeLauncherState.ImportOldConfig(oldConfigPath);
			}
			grenadeLauncherState.statePath = path;
			grenadeLauncherState.Save();
			return grenadeLauncherState;
		}

		internal SlotLoadoutState GetSlot(int slot)
		{
			SlotLoadoutState slotLoadoutState = Slots.FirstOrDefault((SlotLoadoutState item) => item != null && item.Slot == slot);
			if (slotLoadoutState != null)
			{
				return slotLoadoutState;
			}
			slotLoadoutState = new SlotLoadoutState
			{
				Slot = slot
			};
			Slots.Add(slotLoadoutState);
			return slotLoadoutState;
		}

		internal void Save()
		{
			if (string.IsNullOrEmpty(statePath))
			{
				return;
			}
			try
			{
				File.WriteAllText(statePath, JsonUtility.ToJson((object)this, true));
			}
			catch (Exception ex)
			{
				ManualLogSource logSource = Plugin.LogSource;
				if (logSource != null)
				{
					logSource.LogWarning((object)("Could not save Grenade Launcher internal state: " + ex.Message));
				}
			}
		}

		private void ImportOldConfig(string oldConfigPath)
		{
			if (!File.Exists(oldConfigPath))
			{
				return;
			}
			try
			{
				string text = string.Empty;
				string[] array = File.ReadAllLines(oldConfigPath);
				for (int i = 0; i < array.Length; i++)
				{
					string text2 = array[i].Trim();
					if (text2.StartsWith("[") && text2.EndsWith("]"))
					{
						text = text2.Substring(1, text2.Length - 2);
					}
					else
					{
						if (text != "Loadout" || !text2.Contains("="))
						{
							continue;
						}
						string[] array2 = text2.Split(new char[1] { '=' }, 2);
						string text3 = array2[0].Trim();
						if (!bool.TryParse(array2[1].Trim(), out var result) || !text3.StartsWith("SaveSlot"))
						{
							continue;
						}
						int length = "SaveSlot".Length;
						int num = text3.IndexOfAny(new char[3] { 'U', 'R', 'P' }, length);
						if (num <= length || !int.TryParse(text3.Substring(length, num - length), out var result2))
						{
							continue;
						}
						SlotLoadoutState slot = GetSlot(result2);
						if (text3.EndsWith("UsesGrenadeLauncher"))
						{
							if (text3.Contains("RocketVariant0"))
							{
								slot.Blue = result;
							}
							else if (text3.Contains("RocketVariant1"))
							{
								slot.Green = result;
							}
							else if (text3.Contains("RocketVariant2"))
							{
								slot.Red = result;
							}
							else
							{
								slot.LegacyEnabled = result;
							}
						}
						else if (text3.EndsWith("PerVariantLoadoutMigrated"))
						{
							slot.Migrated = result;
						}
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logSource = Plugin.LogSource;
				if (logSource != null)
				{
					logSource.LogWarning((object)("Could not migrate old Grenade Launcher loadout config: " + ex.Message));
				}
			}
		}
	}
	[HarmonyPatch(typeof(LeaderboardController), "SubmitCyberGrindScore")]
	internal static class CyberGrindLeaderboardPatch
	{
		private static bool Prefix()
		{
			ManualLogSource logSource = Plugin.LogSource;
			if (logSource != null)
			{
				logSource.LogInfo((object)"Blocked Cyber Grind leaderboard submission while Grenade Launcher is loaded; local high score remains enabled.");
			}
			return false;
		}
	}
	internal enum GrenadeProjectileProfile
	{
		Primary,
		GreenContact,
		RedBurst,
		BlueDelivery
	}
	internal static class GrenadeSpawnContext
	{
		private static int depth;

		internal static bool Active => depth > 0;

		internal static GrenadeProjectileProfile Profile { get; private set; }

		internal static void Enter(GrenadeProjectileProfile profile = GrenadeProjectileProfile.Primary)
		{
			if (depth == 0)
			{
				Profile = profile;
			}
			depth++;
		}

		internal static void Exit()
		{
			depth = Math.Max(0, depth - 1);
		}

		internal static void Reset()
		{
			depth = 0;
			Profile = GrenadeProjectileProfile.Primary;
		}
	}
	internal static class RocketCooldownSync
	{
		private const float EquipDrawDelay = 0.25f;

		private static readonly FieldRef<RocketLauncher, float> Cooldown = AccessTools.FieldRefAccess<RocketLauncher, float>("cooldown");

		private static float standardReadyAt;

		private static float grenadeReadyAt;

		internal static bool Ready(RocketLauncher launcher)
		{
			if (!CooldownRules.NoWeaponCooldown && !((Object)(object)launcher == (Object)null))
			{
				return Cooldown.Invoke(launcher) <= 0f;
			}
			return true;
		}

		internal static void ApplyAfterShot(RocketLauncher firedLauncher, bool grenadeShot)
		{
			if (CooldownRules.NoWeaponCooldown)
			{
				Reset();
				return;
			}
			float num = Mathf.Max(0f, PluginSettings.FireInterval);
			grenadeReadyAt = Time.time + num;
			standardReadyAt = Time.time + (grenadeShot ? num : Mathf.Max(0f, ((Object)(object)firedLauncher != (Object)null) ? firedLauncher.rateOfFire : 1f));
		}

		internal static void ApplyWhenEquipped(RocketLauncher launcher)
		{
			if (!((Object)(object)launcher == (Object)null))
			{
				if (CooldownRules.NoWeaponCooldown)
				{
					Reset();
					Cooldown.Invoke(launcher) = 0f;
				}
				else
				{
					float num = (((Object)(object)Plugin.Instance != (Object)null && Plugin.Instance.IsGrenadeModeEnabled(launcher)) ? grenadeReadyAt : standardReadyAt);
					Cooldown.Invoke(launcher) = Mathf.Max(0.25f, num - Time.time);
				}
			}
		}

		internal static void Reset()
		{
			standardReadyAt = 0f;
			grenadeReadyAt = 0f;
		}
	}
	internal static class CooldownRules
	{
		internal static bool NoWeaponCooldown => NoWeaponCooldown.NoCooldown;
	}
	[HarmonyPatch(typeof(RocketLauncher), "OnEnable")]
	internal static class RocketLauncherEquipCooldownPatch
	{
		[HarmonyPriority(0)]
		private static void Postfix(RocketLauncher __instance)
		{
			RocketCooldownSync.ApplyWhenEquipped(__instance);
			WeaponVisualRuntime.RegisterLauncher(__instance);
		}
	}
	[HarmonyPatch(typeof(RocketLauncher), "Shoot")]
	internal static class RocketLauncherShootPatch
	{
		private struct State
		{
			internal bool Active;

			internal bool EnteredContext;

			internal bool DualWieldDuplicate;

			internal bool NotifyGreenPrimary;

			internal bool NotifyBluePrimary;

			internal GrenadeProjectileProfile ProjectileProfile;

			internal float RateOfFire;

			internal AudioSource VanillaShotAudio;

			internal bool VanillaShotAudioMuted;

			internal bool VanillaShotAudioOriginalMute;
		}

		private static readonly FieldRef<RocketLauncher, WeaponIdentifier> WeaponId = AccessTools.FieldRefAccess<RocketLauncher, WeaponIdentifier>("wid");

		private static bool Prefix(RocketLauncher __instance, out State __state)
		{
			bool active = (Object)(object)Plugin.Instance != (Object)null && Plugin.Instance.IsGrenadeModeEnabled(__instance);
			WeaponIdentifier val = WeaponId.Invoke(__instance);
			bool dualWieldDuplicate = (Object)(object)val != (Object)null && val.duplicate;
			__state = new State
			{
				Active = active,
				DualWieldDuplicate = dualWieldDuplicate,
				ProjectileProfile = (GrenadeSpawnContext.Active ? GrenadeSpawnContext.Profile : GrenadeProjectileProfile.Primary),
				RateOfFire = __instance.rateOfFire
			};
			if (!__state.Active)
			{
				return true;
			}
			if (WeaponVisualRuntime.ShouldReplaceVanillaShotFeedback(__instance))
			{
				__state.VanillaShotAudio = WeaponVisualRuntime.GetVanillaShotAudio(__instance);
				if ((Object)(object)__state.VanillaShotAudio != (Object)null)
				{
					__state.VanillaShotAudioOriginalMute = __state.VanillaShotAudio.mute;
					__state.VanillaShotAudio.mute = true;
					__state.VanillaShotAudioMuted = true;
				}
			}
			__instance.rateOfFire = PluginSettings.FireInterval;
			if (!GrenadeSpawnContext.Active)
			{
				__state.NotifyGreenPrimary = __instance.variation == 1;
				__state.NotifyBluePrimary = __instance.variation == 0;
				GrenadeSpawnContext.Enter();
				__state.EnteredContext = true;
			}
			return true;
		}

		private static Exception Finalizer(RocketLauncher __instance, State __state, Exception __exception)
		{
			Restore(__instance, __state);
			if (__state.VanillaShotAudioMuted && (Object)(object)__state.VanillaShotAudio != (Object)null)
			{
				__state.VanillaShotAudio.Stop();
				__state.VanillaShotAudio.mute = __state.VanillaShotAudioOriginalMute;
			}
			if (__exception == null && !__state.DualWieldDuplicate)
			{
				RocketCooldownSync.ApplyAfterShot(__instance, __state.Active);
			}
			if (__exception == null && __state.Active)
			{
				WeaponVisualRuntime.NotifyShot(__instance, __state.ProjectileProfile);
			}
			if (__exception == null && __state.NotifyGreenPrimary)
			{
				AlternateFireController.OnGreenPrimaryFired();
			}
			if (__exception == null && __state.NotifyBluePrimary)
			{
				AlternateFireController.OnBluePrimaryFired();
			}
			return __exception;
		}

		private static void Restore(RocketLauncher launcher, State state)
		{
			if (state.Active)
			{
				launcher.rateOfFire = state.RateOfFire;
				if (state.EnteredContext)
				{
					GrenadeSpawnContext.Exit();
				}
			}
		}
	}
	[HarmonyPatch(typeof(CameraController), "CameraShake", new Type[] { typeof(float) })]
	internal static class GrenadeLauncherCameraShakePatch
	{
		private static bool Prefix()
		{
			return !GrenadeSpawnContext.Active;
		}
	}
	[HarmonyPatch(typeof(RocketLauncher), "Clunk")]
	internal static class GrenadeLauncherClunkPatch
	{
		private static bool Prefix(RocketLauncher __instance)
		{
			return !WeaponVisualRuntime.ShouldReplaceVanillaShotFeedback(__instance);
		}
	}
	[HarmonyPatch(typeof(Grenade), "GrenadeBeam")]
	internal static class GrenadeLauncherJackhammerGrenadeBeamTagPatch
	{
		private struct State
		{
			internal bool Tagged;

			internal string OriginalHitter;
		}

		private const string TagPrefix = "grenadelauncher-jackhammer|";

		private static void Prefix(Grenade __instance, GameObject newSourceWeapon, out State __state)
		{
			__state = default(State);
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).GetComponent<GrenadeLauncherProjectile>() == (Object)null) && !((Object)(object)newSourceWeapon == (Object)null) && !((Object)(object)newSourceWeapon.GetComponentInParent<ShotgunHammer>() == (Object)null))
			{
				__state.Tagged = true;
				__state.OriginalHitter = __instance.hitterWeapon;
				__instance.hitterWeapon = "grenadelauncher-jackhammer|" + (__state.OriginalHitter ?? string.Empty);
			}
		}

		private static void Postfix(Grenade __instance, State __state)
		{
			if (__state.Tagged && (Object)(object)__instance != (Object)null)
			{
				__instance.hitterWeapon = __state.OriginalHitter;
			}
		}

		internal static bool TryApply(RevolverBeam beam)
		{
			if ((Object)(object)beam == (Object)null || string.IsNullOrEmpty(beam.hitterOverride) || !beam.hitterOverride.StartsWith("grenadelauncher-jackhammer|", StringComparison.Ordinal))
			{
				return false;
			}
			beam.hitterOverride = beam.hitterOverride.Substring("grenadelauncher-jackhammer|".Length);
			int num = Mathf.RoundToInt(Mathf.Max(0f, PluginSettings.JackhammerGrenadeSelfDamage));
			((Component)beam).gameObject.AddComponent<GrenadeLauncherJackhammerBeamMarker>().SelfDamage = num;
			beam.damage = (float)num / 10f;
			beam.enemyDamageOverride = Mathf.Max(0f, PluginSettings.JackhammerGrenadeDamage);
			return true;
		}
	}
	internal sealed class GrenadeLauncherJackhammerBeamMarker : MonoBehaviour
	{
		internal int SelfDamage;
	}
	internal static class GrenadeLauncherJackhammerBeamDamageContext
	{
		private static readonly Stack<int> selfDamageStack = new Stack<int>();

		private static float delayedExplosionOverrideEndsAt;

		internal static bool Active => selfDamageStack.Count > 0;

		internal static int SelfDamage
		{
			get
			{
				if (!Active)
				{
					return 0;
				}
				return selfDamageStack.Peek();
			}
		}

		internal static bool IsDelayedExplosionOverrideActive => Time.time <= delayedExplosionOverrideEndsAt;

		internal static void StartDelayedExplosionOverride()
		{
			delayedExplosionOverrideEndsAt = Time.time + 2f;
		}

		internal static bool Enter(RevolverBeam beam)
		{
			GrenadeLauncherJackhammerBeamMarker grenadeLauncherJackhammerBeamMarker = (((Object)(object)beam != (Object)null) ? ((Component)beam).GetComponent<GrenadeLauncherJackhammerBeamMarker>() : null);
			if ((Object)(object)grenadeLauncherJackhammerBeamMarker == (Object)null)
			{
				return false;
			}
			selfDamageStack.Push(grenadeLauncherJackhammerBeamMarker.SelfDamage);
			StartDelayedExplosionOverride();
			return true;
		}

		internal static void Exit(bool entered)
		{
			if (entered && selfDamageStack.Count > 0)
			{
				selfDamageStack.Pop();
			}
		}
	}
	[HarmonyPatch(typeof(RevolverBeam), "Start")]
	internal static class GrenadeLauncherJackhammerGrenadeBeamDamagePatch
	{
		private static void Prefix(RevolverBeam __instance)
		{
			GrenadeLauncherJackhammerGrenadeBeamTagPatch.TryApply(__instance);
		}
	}
	[HarmonyPatch(typeof(RevolverBeam), "ExecuteHits")]
	internal static class GrenadeLauncherJackhammerBeamDamageContextPatch
	{
		private static void Prefix(RevolverBeam __instance, out bool __state)
		{
			__state = GrenadeLauncherJackhammerBeamDamageContext.Enter(__instance);
		}

		private static Exception Finalizer(bool __state, Exception __exception)
		{
			GrenadeLauncherJackhammerBeamDamageContext.Exit(__state);
			return __exception;
		}
	}
	[HarmonyPatch(typeof(NewMovement), "GetHurt")]
	internal static class GrenadeLauncherJackhammerSelfDamagePatch
	{
		[HarmonyPriority(0)]
		private static void Prefix(ref int damage)
		{
			if (GrenadeLauncherJackhammerBeamDamageContext.Active)
			{
				damage = GrenadeLauncherJackhammerBeamDamageContext.SelfDamage;
			}
		}
	}
	[HarmonyPatch(typeof(Explosion), "Collide")]
	internal static class GrenadeLauncherJackhammerDelayedExplosionDamagePatch
	{
		private static void Prefix(Explosion __instance, Collider other)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)other == (Object)null) && ((Component)other).CompareTag("Player"))
			{
				string text = (((Object)(object)__instance.sourceWeapon != (Object)null) ? ((Object)__instance.sourceWeapon).name : "<none>");
				bool flag = __instance.rocketExplosion && text.StartsWith("Hammer Saw", StringComparison.Ordinal);
				if (GrenadeLauncherJackhammerBeamDamageContext.IsDelayedExplosionOverrideActive && flag)
				{
					int playerDamageOverride = Mathf.RoundToInt(Mathf.Max(0f, PluginSettings.JackhammerGrenadeSelfDamage));
					__instance.playerDamageOverride = playerDamageOverride;
				}
			}
		}
	}
	[HarmonyPatch(typeof(ObjectTracker), "GetGrenade")]
	internal static class GrenadeLauncherWhiplashPatch
	{
		private static void Postfix(ref Grenade __result)
		{
			if (!((Object)(object)__result == (Object)null))
			{
				GrenadeLauncherProjectile component = ((Component)__result).GetComponent<GrenadeLauncherProjectile>();
				if ((Object)(object)component != (Object)null && !component.CanBeWhiplashed)
				{
					__result = null;
				}
				if ((Object)(object)__result != (Object)null && (Object)(object)((Component)__result).GetComponent<BlueHookDeliveryProjectile>() != (Object)null)
				{
					__result = null;
				}
			}
		}
	}
	internal static class GrenadeLauncherHookContext
	{
		private static int depth;

		internal static bool Active => depth > 0;

		internal static void Enter()
		{
			depth++;
		}

		internal static void Exit()
		{
			depth = Math.Max(0, depth - 1);
		}

		internal static void Reset()
		{
			depth = 0;
		}
	}
	[HarmonyPatch(typeof(HookArm), "FixedUpdate")]
	internal static class GrenadeLauncherHookArmPatch
	{
		private static void Prefix()
		{
			GrenadeLauncherHookContext.Enter();
		}

		private static Exception Finalizer(Exception __exception)
		{
			GrenadeLauncherHookContext.Exit();
			return __exception;
		}
	}
	[HarmonyPatch(typeof(Grenade), "Explode", new Type[]
	{
		typeof(bool),
		typeof(bool),
		typeof(bool),
		typeof(float),
		typeof(bool),
		typeof(GameObject),
		typeof(bool)
	})]
	internal static class GrenadeLauncherHookExplosionPatch
	{
		private static bool Prefix(Grenade __instance)
		{
			if ((Object)(object)((Component)__instance).GetComponent<BlueHookDeliveryProjectile>() != (Object)null)
			{
				return false;
			}
			GrenadeLauncherProjectile component = ((Component)__instance).GetComponent<GrenadeLauncherProjectile>();
			if ((Object)(object)component == (Object)null)
			{
				return true;
			}
			if (component.IsStuck)
			{
				if (StuckDetonationContext.CanCurrentBeamDetonate)
				{
					component.DetonateStuck();
				}
				return false;
			}
			return !GrenadeLauncherHookContext.Active;
		}
	}
	internal static class PluginSettings
	{
		internal const string ArcOriginal = "Original TF2-scaled arc";

		internal const string ArcCustom = "Custom gravity";

		private static StringListField arcPreset;

		private static FloatSliderField damage;

		private static FloatSliderField airshotDamage;

		private static FloatSliderField airshotExplosionSize;

		private static FloatSliderField speed;

		private static FloatSliderField upwardVelocity;

		private static FloatSliderField customGravity;

		private static FloatSliderField fireInterval;

		private static FloatSliderField explosionSize;

		private static FloatSliderField knockback;

		private static FloatSliderField lifetime;

		private static FloatSliderField stuckLifetime;

		private static FloatSliderField surfaceFuse;

		private static FloatSliderField hookFuseGrace;

		private static FloatSliderField surfaceDamage;

		private static FloatSliderField bounceRetention;

		private static FloatSliderField parryDamage;

		private static FloatSliderField parryExplosionSize;

		private static FloatSliderField parrySpeed;

		private static FloatSliderField directSelfDamage;

		private static FloatSliderField surfaceSelfDamage;

		private static FloatSliderField parrySelfDamage;

		private static FloatSliderField jackhammerGrenadeDamage;

		private static FloatSliderField jackhammerGrenadeSelfDamage;

		private static Texture2D configuratorIconTexture;

		private static Sprite configuratorIconSprite;

		private static readonly Dictionary<EnemyType, FloatSliderField> enemyDamageMultipliers = new Dictionary<EnemyType, FloatSliderField>();

		private static readonly Dictionary<EnemyType, float> releaseEnemyDamageDefaults = new Dictionary<EnemyType, float>
		{
			{
				(EnemyType)0,
				100f
			},
			{
				(EnemyType)33,
				120f
			},
			{
				(EnemyType)34,
				100f
			},
			{
				(EnemyType)2,
				100f
			},
			{
				(EnemyType)4,
				100f
			},
			{
				(EnemyType)31,
				200f
			},
			{
				(EnemyType)38,
				175f
			},
			{
				(EnemyType)14,
				125f
			}
		};

		internal static readonly bool EyeHeightScaling = true;

		internal const float FallbackEyeHeight = 2.9f;

		private static FloatSliderField greenCooldown;

		private static FloatSliderField greenSpeed;

		private static FloatSliderField greenUpwardVelocity;

		private static FloatSliderField greenGravity;

		private static FloatSliderField greenDirectDamage;

		private static FloatSliderField greenAirshotDamage;

		private static FloatSliderField greenSurfaceDamage;

		private static FloatSliderField greenDirectExplosionSize;

		private static FloatSliderField greenAirshotExplosionSize;

		private static FloatSliderField greenSurfaceExplosionSize;

		private static FloatSliderField greenDirectSelfDamage;

		private static FloatSliderField greenSurfaceSelfDamage;

		private static FloatSliderField greenKnockback;

		private static FloatSliderField greenLifetime;

		private static FloatSliderField gelProjectileSpeed;

		private static FloatSliderField gelCoveragePerDroplet;

		private static FloatSliderField gelCoverageRequired;

		private static FloatSliderField gelSpotSize;

		private static FloatSliderField stuckDamage;

		private static FloatSliderField greenStuckDamage;

		private static FloatSliderField stuckExplosionSize;

		private static FloatSliderField stuckSelfDamage;

		private static FloatSliderField stuckKnockback;

		private static FloatSliderField stuckChainRadius;

		private static FloatSliderField stuckChainPropagationSpeed;

		private static BoolField enemyCarrierDirectDamage;

		private static BoolField timedFuseDetonatesStuck;

		private static BoolField terrainStuckDetonatesOnEnemyWalkover;

		private static FloatSliderField gelEnemyFireRadius;

		private static FloatSliderField gelEnemyFireBaseDuration;

		private static FloatSliderField gelEnemyFireExtraDuration;

		private static FloatSliderField gelEnemyFireMaximumDuration;

		private static FloatSliderField redBurstDirectDamage;

		private static FloatSliderField redBurstTerrainDamage;

		private static FloatSliderField redBurstEnemyDamage;

		private static FloatSliderField redBurstAirshotDamage;

		private static FloatSliderField redBurstShotCount;

		private static FloatSliderField redBurstDuration;

		private static FloatSliderField redBurstCooldown;

		private static FloatSliderField redBurstKnockback;

		private static FloatSliderField blueDistance;

		private static FloatSliderField blueCooldown;

		private static FloatSliderField blueSlingshotForce;

		private static FloatSliderField bluePointSize;

		private static FloatSliderField blueReplacementDamage;

		private static FloatSliderField blueReplacementExplosionSize;

		private static FloatSliderField blueReplacementForce;

		private static FloatSliderField pinkArmingDelay;

		private static FloatSliderField pinkConductionArmingDelay;

		private static FloatSliderField pinkConductionRearmDelay;

		private static FloatSliderField pinkPullDelay;

		private static FloatSliderField pinkPullRange;

		private static FloatSliderField pinkPullSpeed;

		private static FloatSliderField blueMaximumHookPoints;

		private static FloatSliderField blueGreenHookPoints;

		private static BoolField blueRequireGroundAfterUse;

		private static BoolField blueKnuckleblasterRefundsCooldown;

		private static readonly Dictionary<EnemyType, FloatSliderField> pinkBlastEnemyDamageMultipliers = new Dictionary<EnemyType, FloatSliderField>();

		private static FloatSliderField pipeDreamDistance;

		private static FloatSliderField moonShotDistance;

		private static FloatSliderField pipeDreamStylePoints;

		private static FloatSliderField moonShotStylePoints;

		private static FloatSliderField outSnipedStylePoints;

		private static FloatSliderField walkingBombStylePoints;

		private static FloatSliderField directHitStylePoints;

		private static FloatSliderField pipeDreamDamageMultiplier;

		private static FloatSliderField pipeDreamExplosionSizeMultiplier;

		private static FloatSliderField moonShotDamageMultiplier;

		private static FloatSliderField moonShotExplosionSizeMultiplier;

		internal static float Damage
		{
			get
			{
				FloatSliderField obj = damage;
				if (obj == null)
				{
					return 4.5f;
				}
				return obj.value;
			}
		}

		internal static float AirshotDamage
		{
			get
			{
				FloatSliderField obj = airshotDamage;
				if (obj == null)
				{
					return 7f;
				}
				return obj.value;
			}
		}

		internal static float AirshotExplosionSize
		{
			get
			{
				FloatSliderField obj = airshotExplosionSize;
				if (obj == null)
				{
					return 1f;
				}
				return obj.value;
			}
		}

		internal static float SpeedMultiplier
		{
			get
			{
				FloatSliderField obj = speed;
				if (obj == null)
				{
					return 1f;
				}
				return obj.value;
			}
		}

		internal static float UpwardVelocityMultiplier
		{
			get
			{
				FloatSliderField obj = upwardVelocity;
				if (obj == null)
				{
					return 1f;
				}
				return obj.value;
			}
		}

		internal static float FireInterval
		{
			get
			{
				FloatSliderField obj = fireInterval;
				if (obj == null)
				{
					return 0.6f;
				}
				return obj.value;
			}
		}

		internal static float ExplosionSizeMultiplier
		{
			get
			{
				FloatSliderField obj = explosionSize;
				if (obj == null)
				{
					return 0.9f;
				}
				return obj.value;
			}
		}

		internal static float KnockbackMultiplier
		{
			get
			{
				FloatSliderField obj = knockback;
				if (obj == null)
				{
					return 1f;
				}
				return obj.value;
			}
		}

		internal static float Lifetime
		{
			get
			{
				FloatSliderField obj = lifetime;
				if (obj == null)
				{
					return 15f;
				}
				return obj.value;
			}
		}

		internal static float StuckLifetime
		{
			get
			{
				FloatSliderField obj = stuckLifetime;
				if (obj == null)
				{
					return 60f;
				}
				return obj.value;
			}
		}

		internal static float SurfaceFuse
		{
			get
			{
				FloatSliderField obj = surfaceFuse;
				if (obj == null)
				{
					return 1f;
				}
				return obj.value;
			}
		}

		internal static float HookFuseGrace
		{
			get
			{
				FloatSliderField obj = hookFuseGrace;
				if (obj == null)
				{
					return 0.1f;
				}
				return obj.value;
			}
		}

		internal static float SurfaceDamage
		{
			get
			{
				FloatSliderField obj = surfaceDamage;
				if (obj == null)
				{
					return 3f;
				}
				return obj.value;
			}
		}

		internal static float BounceRetention
		{
			get
			{
				FloatSliderField obj = bounceRetention;
				if (obj == null)
				{
					return 0.1f;
				}
				return obj.value;
			}
		}

		internal static float ParryDamage
		{
			get
			{
				FloatSliderField obj = parryDamage;
				if (obj == null)
				{
					return 4.5f;
				}
				return obj.value;
			}
		}

		internal static float ParryExplosionSize
		{
			get
			{
				FloatSliderField obj = parryExplosionSize;
				if (obj == null)
				{
					return 1f;
				}
				return obj.value;
			}
		}

		internal static float ParrySpeedMultiplier
		{
			get
			{
				FloatSliderField obj = parrySpeed;
				if (obj == null)
				{
					return 3f;
				}
				return obj.value;
			}
		}

		internal static float DirectSelfDamage
		{
			get
			{
				FloatSliderField obj = directSelfDamage;
				if (obj == null)
				{
					return 35f;
				}
				return obj.value;
			}
		}

		internal static float SurfaceSelfDamage
		{
			get
			{
				FloatSliderField obj = surfaceSelfDamage;
				if (obj == null)
				{
					return 25f;
				}
				return obj.value;
			}
		}

		internal static float ParrySelfDamage
		{
			get
			{
				FloatSliderField obj = parrySelfDamage;
				if (obj == null)
				{
					return 30f;
				}
				return obj.value;
			}
		}

		internal static float JackhammerGrenadeDamage
		{
			get
			{
				FloatSliderField obj = jackhammerGrenadeDamage;
				if (obj == null)
				{
					return 10f;
				}
				return obj.value;
			}
		}

		internal static float JackhammerGrenadeSelfDamage
		{
			get
			{
				FloatSliderField obj = jackhammerGrenadeSelfDamage;
				if (obj == null)
				{
					return 35f;
				}
				return obj.value;
			}
		}

		internal static float GravityMultiplier
		{
			get
			{
				StringListField obj = arcPreset;
				if ((((obj != null) ? obj.value : null) ?? "Original TF2-scaled arc") == "Original TF2-scaled arc")
				{
					return 1f;
				}
				FloatSliderField obj2 = customGravity;
				if (obj2 == null)
				{
					return 1f;
				}
				return obj2.value;
			}
		}

		internal static float GreenCooldown
		{
			get
			{
				FloatSliderField obj = greenCooldown;
				if (obj == null)
				{
					return 6f;
				}
				return obj.value;
			}
		}

		internal static float GreenSpeedMultiplier
		{
			get
			{
				FloatSliderField obj = greenSpeed;
				if (obj == null)
				{
					return 1.5f;
				}
				return obj.value;
			}
		}

		internal static float GreenUpwardVelocityMultiplier
		{
			get
			{
				FloatSliderField obj = greenUpwardVelocity;
				if (obj == null)
				{
					return 1f;
				}
				return obj.value;
			}
		}

		internal static float GreenGravityMultiplier
		{
			get
			{
				FloatSliderField obj = greenGravity;
				if (obj == null)
				{
					return 1f;
				}
				return obj.value;
			}
		}

		internal static float GreenDirectDamage
		{
			get
			{
				FloatSliderField obj = greenDirectDamage;
				if (obj == null)
				{
					return 6f;
				}
				return obj.value;
			}
		}

		internal static float GreenAirshotDamage
		{
			get
			{
				FloatSliderField obj = greenAirshotDamage;
				if (obj == null)
				{
					return 8f;
				}
				return obj.value;
			}
		}

		internal static float GreenSurfaceDamage
		{
			get
			{
				FloatSliderField obj = greenSurfaceDamage;
				if (obj == null)
				{
					return 4.5f;
				}
				return obj.value;
			}
		}

		internal static float GreenDirectExplosionSize
		{
			get
			{
				FloatSliderField obj = greenDirectExplosionSize;
				if (obj == null)
				{
					return 1.4f;
				}
				return obj.value;
			}
		}

		internal static float GreenAirshotExplosionSize
		{
			get
			{
				FloatSliderField obj = greenAirshotExplosionSize;
				if (obj == null)
				{
					return 1.5f;
				}
				return obj.value;
			}
		}

		internal static float GreenSurfaceExplosionSize
		{
			get
			{
				FloatSliderField obj = greenSurfaceExplosionSize;
				if (obj == null)
				{
					return 1f;
				}
				return obj.value;
			}
		}

		internal static float GreenDirectSelfDamage
		{
			get
			{
				FloatSliderField obj = greenDirectSelfDamage;
				if (obj == null)
				{
					return 35f;
				}
				return obj.value;
			}
		}

		internal static float GreenSurfaceSelfDamage
		{
			get
			{
				FloatSliderField obj = greenSurfaceSelfDamage;
				if (obj == null)
				{
					return 35f;
				}
				return obj.value;
			}
		}

		internal static float GreenKnockbackMultiplier
		{
			get
			{
				FloatSliderField obj = greenKnockback;
				if (obj == null)
				{
					return 1f;
				}
				return obj.value;
			}
		}

		internal static float GreenLifetime
		{
			get
			{
				FloatSliderField obj = greenLifetime;
				if (obj == null)
				{
					return 15f;
				}
				return obj.value;
			}
		}

		internal static float GelProjectileSpeedMultiplier
		{
			get
			{
				FloatSliderField obj = gelProjectileSpeed;
				if (obj == null)
				{
					return 1f;
				}
				return obj.value;
			}
		}

		internal static float GelCoveragePerDroplet
		{
			get
			{
				FloatSliderField obj = gelCoveragePerDroplet;
				return ((obj != null) ? obj.value : 4f) / 100f;
			}
		}

		internal static float GelCoverageRequired
		{
			get
			{
				FloatSliderField obj = gelCoverageRequired;
				return ((obj != null) ? obj.value : 75f) / 100f;
			}
		}

		internal static float GelSpotSize
		{
			get
			{
				FloatSliderField obj = gelSpotSize;
				if (obj == null)
				{
					return 1.25f;
				}
				return obj.value;
			}
		}

		internal static float StuckDamage
		{
			get
			{
				FloatSliderField obj = stuckDamage;
				if (obj == null)
				{
					return 4.5f;
				}
				return obj.value;
			}
		}

		internal static float GreenStuckDamage
		{
			get
			{
				FloatSliderField obj = greenStuckDamage;
				if (obj == null)
				{
					return 6f;
				}
				return obj.value;
			}
		}

		internal static float StuckExplosionSize
		{
			get
			{
				FloatSliderField obj = stuckExplosionSize;
				if (obj == null)
				{
					return 1.3f;
				}
				return obj.value;
			}
		}

		internal static float StuckSelfDamage
		{
			get
			{
				FloatSliderField obj = stuckSelfDamage;
				if (obj == null)
				{
					return 35f;
				}
				return obj.value;
			}
		}

		internal static float StuckKnockbackMultiplier
		{
			get
			{
				FloatSliderField obj = stuckKnockback;
				if (obj == null)
				{
					return 1f;
				}
				return obj.value;
			}
		}

		internal static float StuckChainRadiusMultiplier
		{
			get
			{
				FloatSliderField obj = stuckChainRadius;
				if (obj == null)
				{
					return 2f;
				}
				return obj.value;
			}
		}

		internal static float StuckChainPropagationSpeed
		{
			get
			{
				FloatSliderField obj = stuckChainPropagationSpeed;
				if (obj == null)
				{
					return 50f;
				}
				return obj.value;
			}
		}

		internal static bool EnemyCarrierTakesDirectDamage
		{
			get
			{
				BoolField obj = enemyCarrierDirectDamage;
				if (obj == null)
				{
					return false;
				}
				return obj.value;
			}
		}

		internal static bool TimedFuseDetonatesStuck
		{
			get
			{
				BoolField obj = timedFuseDetonatesStuck;
				if (obj == null)
				{
					return false;
				}
				return obj.value;
			}
		}

		internal static bool TerrainStuckDetonatesOnEnemyWalkover
		{
			get
			{
				BoolField obj = terrainStuckDetonatesOnEnemyWalkover;
				if (obj == null)
				{
					return false;
				}
				return obj.value;
			}
		}

		internal static float GelEnemyFireRadiusMultiplier
		{
			get
			{
				FloatSliderField obj = gelEnemyFireRadius;
				if (obj == null)
				{
					return 2.5f;
				}
				return obj.value;
			}
		}

		internal static float GelEnemyFireBaseDuration
		{
			get
			{
				FloatSliderField obj = gelEnemyFireBaseDuration;
				if (obj == null)
				{
					return 3f;
				}
				return obj.value;
			}
		}

		internal static float GelEnemyFireExtraDuration
		{
			get
			{
				FloatSliderField obj = gelEnemyFireExtraDuration;
				if (obj == null)
				{
					return 1f;
				}
				return obj.value;
			}
		}

		internal static float GelEnemyFireMaximumDuration
		{
			get
			{
				FloatSliderField obj = gelEnemyFireMaximumDuration;
				if (obj == null)
				{
					return 8f;
				}
				return obj.value;
			}
		}

		internal static float RedBurstDirectDamage
		{
			get
			{
				FloatSliderField obj = redBurstDirectDamage;
				if (obj == null)
				{
					return 2.5f;
				}
				return obj.value;
			}
		}

		internal static float RedBurstTerrainDamage
		{
			get
			{
				FloatSliderField obj = redBurstTerrainDamage;
				if (obj == null)
				{
					return 3f;
				}
				return obj.value;
			}
		}

		internal static float RedBurstEnemyDamage
		{
			get
			{
				FloatSliderField obj = redBurstEnemyDamage;
				if (obj == null)
				{
					return 2.5f;
				}
				return obj.value;
			}
		}

		internal static float RedBurstAirshotDamage
		{
			get
			{
				FloatSliderField obj = redBurstAirshotDamage;
				if (obj == null)
				{
					return 3.5f;
				}
				return obj.value;
			}
		}

		internal static int RedBurstShotCount
		{
			get
			{
				FloatSliderField obj = redBurstShotCount;
				return Mathf.Max(1, Mathf.RoundToInt((obj != null) ? obj.value : 3f));
			}
		}

		internal static float RedBurstDuration
		{
			get
			{
				FloatSliderField obj = redBurstDuration;
				if (obj == null)
				{
					return 0.3f;
				}
				return obj.value;
			}
		}

		internal static float RedBurstCooldown
		{
			get
			{
				FloatSliderField obj = redBurstCooldown;
				if (obj == null)
				{
					return 4.5f;
				}
				return obj.value;
			}
		}

		internal static float RedBurstKnockbackMultiplier
		{
			get
			{
				FloatSliderField obj = redBurstKnockback;
				if (obj == null)
				{
					return 0.4f;
				}
				return obj.value;
			}
		}

		internal static float BlueDistance
		{
			get
			{
				FloatSliderField obj = blueDistance;
				if (obj == null)
				{
					return 20f;
				}
				return obj.value;
			}
		}

		internal static float BlueCooldown
		{
			get
			{
				FloatSliderField obj = blueCooldown;
				if (obj == null)
				{
					return 4f;
				}
				return obj.value;
			}
		}

		internal static float BlueSlingshotForce
		{
			get
			{
				FloatSliderField obj = blueSlingshotForce;
				if (obj == null)
				{
					return 0f;
				}
				return obj.value;
			}
		}

		internal static float BluePointSize
		{
			get
			{
				FloatSliderField obj = bluePointSize;
				if (obj == null)
				{
					return 1f;
				}
				return obj.value;
			}
		}

		internal static float BlueReplacementDamage
		{
			get
			{
				FloatSliderField obj = blueReplacementDamage;
				if (obj == null)
				{
					return 3.5f;
				}
				return obj.value;
			}
		}

		internal static float BlueReplacementExplosionSize
		{
			get
			{
				FloatSliderField obj = blueReplacementExplosionSize;
				if (obj == null)
				{
					return 1.2f;
				}
				return obj.value;
			}
		}

		internal static float BlueReplacementForce
		{
			get
			{
				FloatSliderField obj = blueReplacementForce;
				if (obj == null)
				{
					return 20000f;
				}
				return obj.value;
			}
		}

		internal static float PinkFirstArmDelay
		{
			get
			{
				FloatSliderField obj = pinkArmingDelay;
				if (obj == null)
				{
					return 2.25f;
				}
				return obj.value;
			}
		}

		internal static float PinkRearmDelay
		{
			get
			{
				FloatSliderField obj = pinkConductionArmingDelay;
				if (obj == null)
				{
					return 3.5f;
				}
				return obj.value;
			}
		}

		internal static float PinkConductionRearmDelay
		{
			get
			{
				FloatSliderField obj = pinkConductionRearmDelay;
				if (obj == null)
				{
					return 5f;
				}
				return obj.value;
			}
		}

		internal static int BlueMaximumHookPoints
		{
			get
			{
				FloatSliderField obj = blueMaximumHookPoints;
				return Mathf.Max(1, Mathf.RoundToInt((obj != null) ? obj.value : 1f));
			}
		}

		internal static int BlueGreenHookPoints
		{
			get
			{
				FloatSliderField obj = blueGreenHookPoints;
				return Mathf.Max(0, Mathf.RoundToInt((obj != null) ? obj.value : 0f));
			}
		}

		internal static bool BlueRequireGroundAfterUse
		{
			get
			{
				BoolField obj = blueRequireGroundAfterUse;
				if (obj == null)
				{
					return false;
				}
				return obj.value;
			}
		}

		internal static bool BlueKnuckleblasterRefundsCooldown
		{
			get
			{
				BoolField obj = blueKnuckleblasterRefundsCooldown;
				if (obj == null)
				{
					return true;
				}
				return obj.value;
			}
		}

		internal static float PinkPullDelay
		{
			get
			{
				FloatSliderField obj = pinkPullDelay;
				if (obj == null)
				{
					return 0.5f;
				}
				return obj.value;
			}
		}

		internal static float PinkPullRange
		{
			get
			{
				FloatSliderField obj = pinkPullRange;
				if (obj == null)
				{
					return 30f;
				}
				return obj.value;
			}
		}

		internal static float PinkPullSpeed
		{
			get
			{
				FloatSliderField obj = pinkPullSpeed;
				if (obj == null)
				{
					return 50f;
				}
				return obj.value;
			}
		}

		internal static float PipeDreamMinimumDistance
		{
			get
			{
				FloatSliderField obj = pipeDreamDistance;
				if (obj == null)
				{
					return 56f;
				}
				return obj.value;
			}
		}

		internal static float MoonShotMinimumDistance
		{
			get
			{
				FloatSliderField obj = moonShotDistance;
				if (obj == null)
				{
					return 125f;
				}
				return obj.value;
			}
		}

		internal static int PipeDreamStylePoints
		{
			get
			{
				FloatSliderField obj = pipeDreamStylePoints;
				return Mathf.RoundToInt((obj != null) ? obj.value : 150f);
			}
		}

		internal static int MoonShotStylePoints
		{
			get
			{
				FloatSliderField obj = moonShotStylePoints;
				return Mathf.RoundToInt((obj != null) ? obj.value : 550f);
			}
		}

		internal static int OutSnipedStylePoints
		{
			get
			{
				FloatSliderField obj = outSnipedStylePoints;
				return Mathf.RoundToInt((obj != null) ? obj.value : 550f);
			}
		}

		internal static int WalkingBombStylePoints
		{
			get
			{
				FloatSliderField obj = walkingBombStylePoints;
				return Mathf.RoundToInt((obj != null) ? obj.value : 90f);
			}
		}

		internal static int DirectHitStylePoints
		{
			get
			{
				FloatSliderField obj = directHitStylePoints;
				return Mathf.RoundToInt((obj != null) ? obj.value : 35f);
			}
		}

		internal static float PipeDreamDamageMultiplier
		{
			get
			{
				FloatSliderField obj = pipeDreamDamageMultiplier;
				if (obj == null)
				{
					return 1f;
				}
				return obj.value;
			}
		}

		internal static float PipeDreamExplosionSizeMultiplier
		{
			get
			{
				FloatSliderField obj = pipeDreamExplosionSizeMultiplier;
				if (obj == null)
				{
					return 1f;
				}
				return obj.value;
			}
		}

		internal static float MoonShotDamageMultiplier
		{
			get
			{
				FloatSliderField obj = moonShotDamageMultiplier;
				if (obj == null)
				{
					return 1.15f;
				}
				return obj.value;
			}
		}

		internal static float MoonShotExplosionSizeMultiplier
		{
			get
			{
				FloatSliderField obj = moonShotExplosionSizeMultiplier;
				if (obj == null)
				{
					return 1.15f;
				}
				return obj.value;
			}
		}

		internal static float GetEnemyDamageMultiplier(EnemyType enemyType)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			if (!enemyDamageMultipliers.TryGetValue(enemyType, out var value))
			{
				return 1f;
			}
			return Mathf.Max(0f, value.value) / 100f;
		}

		internal unsafe static void Initialize()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_042f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0435: Expected O, but got Unknown
			//IL_049d: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_04aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e0: Unknown result type (might be due to invalid IL or missing references)
			PluginConfigurator val = PluginConfigurator.Create("Grenade Launcher", "docvalentyne.ultrakill.grenadelauncher");
			ApplyConfiguratorIcon(val);
			new ConfigHeader(val.rootPanel, "Detailed weapon documentation available on the Wiki tab in the Thunderstore mod page.", 24);
			AddPageResetButton(val.rootPanel, "Reset all pages to default", "resetAllPages", allPages: true, val);
			AddPageResetButton(val.rootPanel, "Reset this page to default", "resetMainPage", allPages: false, val);
			arcPreset = new StringListField(val.rootPanel, "Arc preset", "arcPreset", new string[2] { "Original TF2-scaled arc", "Custom gravity" }, "Original TF2-scaled arc");
			damage = Slider(val, "Damage", "damage", 0f, 10f, 4.5f, 2);
			airshotDamage = Slider(val, "Airshot damage", "airshotDamage", 0f, 20f, 7f, 2);
			airshotExplosionSize = Slider(val, "Airshot explosion size", "airshotExplosionSize", 0.1f, 5f, 1f, 2);
			speed = Slider(val, "Projectile speed multiplier", "speedMultiplier", 0.1f, 3f, 1f, 2);
			upwardVelocity = Slider(val, "Upward velocity multiplier", "upwardVelocityMultiplier", 0f, 3f, 1f, 2);
			customGravity = Slider(val, "Custom gravity multiplier", "customGravityMultiplier", 0.1f, 5f, 1f, 2);
			fireInterval = Slider(val, "Fire interval (seconds)", "fireInterval", 0.1f, 2f, 0.6f, 2);
			explosionSize = Slider(val, "Explosion size (rocket = 1)", "explosionSizeMultiplier", 0.25f, 3f, 0.9f, 2);
			knockback = Slider(val, "Blast knockback (Rocket = 1)", "knockbackMultiplier", 0f, 3f, 1f, 2);
			lifetime = Slider(val, "Silent projectile lifetime", "projectileLifetime", 1f, 60f, 15f, 1);
			stuckLifetime = Slider(val, "Stuck lifetime (seconds)", "stuckLifetime", 1f, 300f, 60f, 1);
			surfaceFuse = Slider(val, "Surface fuse (seconds)", "surfaceFuse", 0.1f, 10f, 1f, 2);
			hookFuseGrace = Slider(val, "Fuse time per Whiplash (s)", "hookFuseGrace", 0f, 2f, 0.1f, 2);
			surfaceDamage = Slider(val, "Surface detonation damage", "surfaceDamage", 0f, 10f, 3f, 2);
			bounceRetention = Slider(val, "Surface bounce speed retention", "bounceRetention", 0f, 1f, 0.1f, 2);
			parryDamage = Slider(val, "Parried grenade damage", "parryDamage", 0f, 20f, 4.5f, 2);
			parryExplosionSize = Slider(val, "Parried blast size (Rocket = 1)", "parryExplosionSize", 0.25f, 5f, 1f, 2);
			parrySpeed = Slider(val, "Parried speed multiplier", "parrySpeedMultiplier", 0.1f, 5f, 3f, 2);
			directSelfDamage = Slider(val, "Direct self-damage (HP)", "directSelfDamage", 0f, 100f, 35f, 0);
			surfaceSelfDamage = Slider(val, "Timed self-damage (HP)", "surfaceSelfDamage", 0f, 100f, 25f, 0);
			parrySelfDamage = Slider(val, "Parried self-damage (HP)", "parrySelfDamage", 0f, 100f, 30f, 0);
			jackhammerGrenadeDamage = Slider(val, "Jackhammer hit damage", "jackhammerGrenadeDamage", 0f, 50f, 10f, 2);
			jackhammerGrenadeSelfDamage = Slider(val, "Jackhammer self-damage (HP)", "jackhammerGrenadeSelfDamage", 0f, 100f, 35f, 0);
			if (arcPreset.value == "Current snappier arc")
			{
				arcPreset.value = "Custom gravity";
				customGravity.value = 2f;
			}
			InitializeAlternateSettings(val);
			WeaponVisualRuntime.InitializeConfiguration(val);
			ConfigPanel val2 = new ConfigPanel(val.rootPanel, "Enemy grenade damage", "enemyDamageMultipliers");
			val2.headerText = "Damage percentage is applied after ULTRAKILL's normal explosive weakness or resistance.";
			AddPageResetButton(val2, "Reset this page to default", "resetEnemyDamageMultipliers");
			enemyDamageMultipliers.Clear();
			foreach (EnemyType item in from EnemyType val3 in Enum.GetValues(typeof(EnemyType))
				orderby ((object)(*(EnemyType*)(&val3))/*cast due to .constrained prefix*/).ToString()
				select val3)
			{
				enemyDamageMultipliers[item] = Slider(val2, FriendlyEnemyName(item) + " damage (%)", "enemyDamage_" + ((object)(*(EnemyType*)(&item))/*cast due to .constrained prefix*/).ToString(), 0f, 500f, releaseEnemyDamageDefaults.TryGetValue(item, out var value) ? value : 100f, 0);
			}
			MigrateBalanceDefaults(val);
		}

		private static void ApplyConfiguratorIcon(PluginConfigurator configurator)
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			using Stream stream = typeof(Plugin).Assembly.GetManifestResourceStream("GrenadeLauncherMod.icon.png");
			if (stream == null)
			{
				ManualLogSource logSource = Plugin.LogSource;
				if (logSource != null)
				{
					logSource.LogWarning((object)"Embedded Plugin Configurator icon was not found.");
				}
				return;
			}
			byte[] array = new byte[stream.Length];
			int i;
			int num;
			for (i = 0; i < array.Length; i += num)
			{
				num = stream.Read(array, i, array.Length - i);
				if (num <= 0)
				{
					break;
				}
			}
			if (i != array.Length)
			{
				ManualLogSource logSource2 = Plugin.LogSource;
				if (logSource2 != null)
				{
					logSource2.LogWarning((object)"Embedded Plugin Configurator icon could not be read completely.");
				}
				return;
			}
			configuratorIconTexture = new Texture2D(2, 2, (TextureFormat)4, false);
			((Object)configuratorIconTexture).name = "Grenade Launcher Icon";
			if (!ImageConversion.LoadImage(configuratorIconTexture, array, false))
			{
				Object.Destroy((Object)(object)configuratorIconTexture);
				configuratorIconTexture = null;
				ManualLogSource logSource3 = Plugin.LogSource;
				if (logSource3 != null)
				{
					logSource3.LogWarning((object)"Embedded Plugin Configurator icon was not a valid image.");
				}
			}
			else
			{
				configuratorIconSprite = Sprite.Create(configuratorIconTexture, new Rect(0f, 0f, (float)((Texture)configuratorIconTexture).width, (float)((Texture)configuratorIconTexture).height), new Vector2(0.5f, 0.5f));
				((Object)configuratorIconSprite).name = "Grenade Launcher Icon";
				configurator.icon = configuratorIconSprite;
			}
		}

		private static void AddPageResetButton(ConfigPanel panel, string text, string guid, bool allPages = false, PluginConfigurator configurator = null)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			new ButtonField(panel, text, guid).onClick += (OnClick)delegate
			{
				PluginConfigurator configurator2 = configurator ?? ((ConfigField)panel).rootConfig;
				if (allPages)
				{
					ResetAllPages(configurator2);
				}
				else
				{
					ResetPage(panel, configurator2);
				}
			};
		}

		private static void ResetPage(ConfigPanel panel, PluginConfigurator configurator)
		{
			foreach (ConfigField directField in GetDirectFields(panel, configurator))
			{
				if (directField != null && !(directField is ConfigPanel) && !(directField is ButtonField))
				{
					ReloadFieldDefault(directField);
				}
			}
			FlushConfigurator(configurator);
		}

		private static IEnumerable<ConfigField> GetDirectFields(ConfigPanel panel, PluginConfigurator configurator)
		{
			IDictionary dictionary = AccessTools.Field(typeof(PluginConfigurator), "fields")?.GetValue(configurator) as IDictionary;
			PropertyInfo parentPanel = AccessTools.Property(typeof(ConfigField), "parentPanel");
			if (dictionary != null && parentPanel != null)
			{
				foreach (object value in dictionary.Values)
				{
					ConfigField val = (ConfigField)((value is ConfigField) ? value : null);
					if (val != null && parentPanel.GetValue(val, null) == panel)
					{
						yield return val;
					}
				}
			}
			else
			{
				ConfigField[] allFields = panel.GetAllFields();
				for (int i = 0; i < allFields.Length; i++)
				{
					yield return allFields[i];
				}
			}
		}

		private static void ResetAllPages(PluginConfigurator configurator)
		{
			if (AccessTools.Field(typeof(PluginConfigurator), "fields")?.GetValue(configurator) is IDictionary dictionary)
			{
				foreach (object value in dictionary.Values)
				{
					ConfigField val = (ConfigField)((value is ConfigField) ? value : null);
					if (val != null && !(val is ConfigPanel) && !(val is ButtonField))
					{
						ReloadFieldDefault(val);
					}
				}
			}
			else
			{
				ResetPage(configurator.rootPanel, configurator);
			}
			FlushConfigurator(configurator);
		}

		private static void ReloadFieldDefault(ConfigField field)
		{
			AccessTools.Method(((object)field).GetType(), "ReloadDefault", (Type[])null, (Type[])null)?.Invoke(field, null);
		}

		private static void FlushConfigurator(PluginConfigurator configurator)
		{
			if (configurator != null)
			{
				AccessTools.Method(typeof(PluginConfigurator), "FlushAll", (Type[])null, (Type[])null)?.Invoke(configurator, null);
				Plugin instance = Plugin.Instance;
				if (instance != null)
				{
					((BaseUnityPlugin)instance).Config.Save();
				}
			}
		}

		private static FloatSliderField Slider(PluginConfigurator configurator, string displayName, string guid, float minimum, float maximum, float defaultValue, int decimals)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			return new FloatSliderField(configurator.rootPanel, displayName, guid, new Tuple<float, float>(minimum, maximum), defaultValue, decimals);
		}

		private static FloatSliderField Slider(ConfigPanel panel, string displayName, string guid, float minimum, float maximum, float defaultValue, int decimals)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			return new FloatSliderField(panel, displayName, guid, new Tuple<float, float>(minimum, maximum), defaultValue, decimals);
		}

		private unsafe static string FriendlyEnemyName(EnemyType enemyType)
		{
			string text = ((object)(*(EnemyType*)(&enemyType))/*cast due to .constrained prefix*/).ToString();
			StringBuilder stringBuilder = new StringBuilder(text.Length + 8);
			for (int i = 0; i < text.Length; i++)
			{
				char c = text[i];
				if (i > 0 && char.IsUpper(c) && !char.IsUpper(text[i - 1]))
				{
					stringBuilder.Append(' ');
				}
				stringBuilder.Append(c);
			}
			return stringBuilder.ToString();
		}

		private static void MigrateBalanceDefaults(PluginConfigurator configurator)
		{
			GrenadeLauncherState grenadeLauncherState = (((Object)(object)Plugin.Instance != (Object)null) ? Plugin.Instance.State : null);
			if (grenadeLauncherState != null)
			{
				if (grenadeLauncherState.BalanceDefaultsVersion < 4)
				{
					ReplaceReleasedDefault(damage, 4.5f, 3f, 4f);
					ReplaceReleasedDefault(airshotDamage, 7f, 6f);
					ReplaceReleasedDefault(surfaceDamage, 3f, 2.5f);
					ReplaceReleasedDefault(greenAirshotDamage, 8f, 7.5f);
					ReplaceReleasedDefault(greenSurfaceDamage, 4.5f, 4f);
					ReplaceReleasedDefault(stuckDamage, 4.5f, 4f);
					ReplaceReleasedDefault(stuckSelfDamage, 35f, 45f);
					ReplaceReleasedDefault(blueDistance, 20f, 27f);
					ReplaceEnemyReleasedDefault((EnemyType)33, 120f, 100f, 110f);
					ReplaceEnemyReleasedDefault((EnemyType)34, 120f, 100f);
					ReplaceEnemyReleasedDefault((EnemyType)2, 100f, 80f, 85f, 90f);
					ReplaceReleasedDefault(pinkArmingDelay, 2.5f, 2f);
					ReplaceReleasedDefault(enemyCarrierDirectDamage, false, true);
					grenadeLauncherState.BalanceDefaultsVersion = 4;
				}
				if (grenadeLauncherState.BalanceDefaultsVersion < 5)
				{
					ReplaceReleasedDefault(pinkArmingDelay, 2.25f, 2f, 2.5f);
					ReplaceReleasedDefault(pinkConductionArmingDelay, 3f, 4f);
					grenadeLauncherState.BalanceDefaultsVersion = 5;
				}
				if (grenadeLauncherState.BalanceDefaultsVersion < 6)
				{
					ReplaceReleasedDefault(gelEnemyFireRadius, 2.5f, 3f);
					ReplaceReleasedDefault(redBurstCooldown, 4.5f, 5f);
					ReplaceReleasedDefault(blueMaximumHookPoints, 1f, 3f);
					ReplaceReleasedDefault(blueGreenHookPoints, 0f, 1f);
					ReplaceReleasedDefault(blueKnuckleblasterRefundsCooldown, true, default(bool));
					ReplaceReleasedDefault(pinkConductionArmingDelay, 3.5f, 3f);
					ReplaceReleasedDefault(pinkConductionRearmDelay, 5f, 4f);
					ReplacePinkBlastReleasedDefault((EnemyType)1, 50f, 100f);
					ReplacePinkBlastReleasedDefault((EnemyType)15, 60f, 100f);
					ReplacePinkBlastReleasedDefault((EnemyType)12, 75f, 100f);
					ReplacePinkBlastReleasedDefault((EnemyType)13, 35f, 100f);
					grenadeLauncherState.BalanceDefaultsVersion = 6;
				}
				if (grenadeLauncherState.BalanceDefaultsVersion < 7)
				{
					ReplaceEnemyReleasedDefault((EnemyType)0, 100f, 120f);
					ReplaceEnemyReleasedDefault((EnemyType)34, 100f, 120f);
					grenadeLauncherState.BalanceDefaultsVersion = 7;
				}
				if (configurator != null)
				{
					configurator.FlushAll();
				}
				grenadeLauncherState.Save();
			}
		}

		private static void ReplaceReleasedDefault(FloatSliderField field, float replacement, params float[] releasedValues)
		{
			if (field != null && releasedValues.Any((float value) => Mathf.Approximately(field.value, value)))
			{
				field.value = replacement;
			}
		}

		private static void ReplaceReleasedDefault(BoolField field, bool replacement, params bool[] releasedValues)
		{
			if (field != null && releasedValues.Contains(field.value))
			{
				field.value = replacement;
			}
		}

		private static void ReplaceEnemyReleasedDefault(EnemyType enemyType, float replacement, params float[] releasedValues)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			if (enemyDamageMultipliers.TryGetValue(enemyType, out var value))
			{
				ReplaceReleasedDefault(value, replacement, releasedValues);
			}
		}

		private static void ReplacePinkBlastReleasedDefault(EnemyType enemyType, float replacement, params float[] releasedValues)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			if (pinkBlastEnemyDamageMultipliers.TryGetValue(enemyType, out var value))
			{
				ReplaceReleasedDefault(value, replacement, releasedValues);
			}
		}

		internal static float GetPinkBlastEnemyDamageMultiplier(EnemyType enemyType)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (!pinkBlastEnemyDamageMultipliers.TryGetValue(enemyType, out var value))
			{
				return GetPinkBlastDefaultDamagePercent(enemyType) / 100f;
			}
			return Mathf.Max(0f, value.value) / 100f;
		}

		internal static float GetPinkBlastDefaultDamagePercent(EnemyType enemyType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected I4, but got Unknown
			if ((int)enemyType != 1)
			{
				return (enemyType - 12) switch
				{
					3 => 60f, 
					0 => 75f, 
					1 => 35f, 
					_ => 100f, 
				};
			}
			return 50f;
		}

		private unsafe static void InitializeAlternateSettings(PluginConfigurator configurator)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Expected O, but got Unknown
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Expected O, but got Unknown
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Expected O, but got Unknown
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Expected O, but got Unknown
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Expected O, but got Unknown
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Expected O, but got Unknown
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Expected O, but got Unknown
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Expected O, but got Unknown
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Expected O, but got Unknown
			//IL_0227: Expected O, but got Unknown
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Expected O, but got Unknown
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Expected O, but got Unknown
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Expected O, but got Unknown
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Expected O, but got Unknown
			//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Expected O, but got Unknown
			//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Expected O, but got Unknown
			//IL_030c: Unknown result type (might be due to invalid IL or missing references)
			//IL_032c: Expected O, but got Unknown
			//IL_0331: Unknown result type (might be due to invalid IL or missing references)
			//IL_0351: Expected O, but got Unknown
			//IL_0356: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: Expected O, but got Unknown
			//IL_037b: Unknown result type (might be due to invalid IL or missing references)
			//IL_039b: Expected O, but got Unknown
			//IL_03a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c0: Expected O, but got Unknown
			//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e5: Expected O, but got Unknown
			//IL_03ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fb: Expected O, but got Unknown
			//IL_03f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0400: Expected O, but got Unknown
			//IL_0400: Unknown result type (might be due to invalid IL or missing references)
			//IL_0411: Expected O, but got Unknown
			//IL_040c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0416: Expected O, but got Unknown
			//IL_0416: Unknown result type (might be due to invalid IL or missing references)
			//IL_0427: Expected O, but got Unknown
			//IL_0422: Unknown result type (might be due to invalid IL or missing references)
			//IL_042c: Expected O, but got Unknown
			//IL_042c: Unknown result type (might be due to invalid IL or missing references)
			//IL_044c: Expected O, but got Unknown
			//IL_0451: Unknown result type (might be due to invalid IL or missing references)
			//IL_0471: Expected O, but got Unknown
			//IL_0476: Unknown result type (might be due to invalid IL or missing references)
			//IL_0496: Expected O, but got Unknown
			//IL_049b: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bb: Expected O, but got Unknown
			//IL_04cf: Expected O, but got Unknown
			//IL_04ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e1: Expected O, but got Unknown
			//IL_04e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0501: Expected O, but got Unknown
			//IL_0506: Unknown result type (might be due to invalid IL or missing references)
			//IL_0526: Expected O, but got Unknown
			//IL_052b: Unknown result type (might be due to invalid IL or missing references)
			//IL_054b: Expected O, but got Unknown
			//IL_0550: Unknown result type (might be due to invalid IL or missing references)
			//IL_0570: Expected O, but got Unknown
			//IL_0575: Unknown result type (might be due to invalid IL or missing references)
			//IL_0595: Expected O, but got Unknown
			//IL_059a: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ba: Expected O, but got Unknown
			//IL_05bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_05df: Expected O, but got Unknown
			//IL_0603: Expected O, but got Unknown
			//IL_0618: Unknown result type (might be due to invalid IL or missing references)
			//IL_061d: Unknown result type (might be due to invalid IL or missing references)
			//IL_062f: Expected O, but got Unknown
			//IL_062f: Unknown result type (might be due to invalid IL or missing references)
			//IL_064f: Expected O, but got Unknown
			//IL_0654: Unknown result type (might be due to invalid IL or missing references)
			//IL_0674: Expected O, but got Unknown
			//IL_0679: Unknown result type (might be due to invalid IL or missing references)
			//IL_0699: Expected O, but got Unknown
			//IL_069e: Unknown result type (might be due to invalid IL or missing references)
			//IL_06be: Expected O, but got Unknown
			//IL_06c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e3: Expected O, but got Unknown
			//IL_06e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0708: Expected O, but got Unknown
			//IL_070d: Unknown result type (might be due to invalid IL or missing references)
			//IL_071e: Expected O, but got Unknown
			//IL_0719: Unknown result type (might be due to invalid IL or missing references)
			//IL_0723: Expected O, but got Unknown
			//IL_0723: Unknown result type (might be due to invalid IL or missing references)
			//IL_0734: Expected O, but got Unknown
			//IL_072f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0739: Expected O, but got Unknown
			//IL_0739: Unknown result type (might be due to invalid IL or missing references)
			//IL_0759: Expected O, but got Unknown
			//IL_075e: Unknown result type (might be due to invalid IL or missing references)
			//IL_077e: Expected O, but got Unknown
			//IL_0783: Unknown result type (might be due to invalid IL or missing references)
			//IL_07a3: Expected O, but got Unknown
			//IL_07a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_07c8: Expected O, but got Unknown
			//IL_07cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_07ed: Expected O, but got Unknown
			//IL_07f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0812: Expected O, but got Unknown
			//IL_0817: Unknown result type (might be due to invalid IL or missing references)
			//IL_0837: Expected O, but got Unknown
			//IL_083c: Unknown result type (might be due to invalid IL or missing references)
			//IL_085c: Expected O, but got Unknown
			//IL_0861: Unknown result type (might be due to invalid IL or missing references)
			//IL_0881: Expected O, but got Unknown
			//IL_0895: Expected O, but got Unknown
			//IL_0890: Unknown result type (might be due to invalid IL or missing references)
			//IL_0896: Expected O, but got Unknown
			//IL_08fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0903: Unknown result type (might be due to invalid IL or missing references)
			//IL_0909: Unknown result type (might be due to invalid IL or missing references)
			//IL_090b: Unknown result type (might be due to invalid IL or missing references)
			//IL_093c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0971: Unknown result type (might be due to invalid IL or missing references)
			//IL_0976: Unknown result type (might be due to invalid IL or missing references)
			//IL_0988: Expected O, but got Unknown
			//IL_0988: Unknown result type (might be due to invalid IL or missing references)
			//IL_09a8: Expected O, but got Unknown
			//IL_09ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_09cd: Expected O, but got Unknown
			//IL_09d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_09f2: Expected O, but got Unknown
			//IL_09f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a17: Expected O, but got Unknown
			//IL_0a1c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a3c: Expected O, but got Unknown
			//IL_0a41: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a61: Expected O, but got Unknown
			//IL_0a66: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a86: Expected O, but got Unknown
			//IL_0a8b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0aab: Expected O, but got Unknown
			//IL_0ab0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ad0: Expected O, but got Unknown
			//IL_0ad5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0af5: Expected O, but got Unknown
			//IL_0b19: Expected O, but got Unknown
			ConfigPanel val = new ConfigPanel(configurator.rootPanel, "Green contact grenade", "greenContactGrenade");
			AddPageResetButton(val, "Reset this page to default", "resetGreenContactGrenade");
			greenCooldown = Slider(val, "Cooldown (seconds)", "greenCooldown", 0.05f, 10f, 6f, 2);
			greenSpeed = Slider(val, "Projectile speed multiplier", "greenSpeedMultiplier", 0.1f, 5f, 1.5f, 2);
			greenUpwardVelocity = Slider(val, "Upward velocity multiplier", "greenUpwardVelocityMultiplier", 0f, 5f, 1f, 2);
			greenGravity = Slider(val, "Gravity multiplier", "greenGravityMultiplier", 0.1f, 5f, 1f, 2);
			greenDirectDamage = Slider(val, "Direct hit damage", "greenDirectDamage", 0f, 20f, 6f, 2);
			greenAirshotDamage = Slider(val, "Airshot damage", "greenAirshotDamage", 0f, 25f, 8f, 2);
			greenSurfaceDamage = Slider(val, "Surface contact damage", "greenSurfaceDamage", 0f, 20f, 4.5f, 2);
			greenDirectExplosionSize = Slider(val, "Direct blast size (Rocket = 1)", "greenDirectExplosionSize", 0.1f, 5f, 1.4f, 2);
			greenAirshotExplosionSize = Slider(val, "Airshot explosion size", "greenAirshotExplosionSize", 0.1f, 5f, 1.5f, 2);
			greenSurfaceExplosionSize = Slider(val, "Surface blast size (Rocket = 1)", "greenSurfaceExplosionSize", 0.1f, 5f, 1f, 2);
			greenDirectSelfDamage = Slider(val, "Direct self damage (HP)", "greenDirectSelfDamage", 0f, 100f, 35f, 0);
			greenSurfaceSelfDamage = Slider(val, "Surface self damage (HP)", "greenSurfaceSelfDamage", 0f, 100f, 35f, 0);
			greenKnockback = Slider(val, "Blast knockback (Rocket = 1)", "greenKnockbackMultiplier", 0f, 5f, 1f, 2);
			greenLifetime = Slider(val, "Silent projectile lifetime", "greenLifetime", 1f, 60f, 15f, 1);
			ConfigPanel val2 = new ConfigPanel(configurator.rootPanel, "Red blue-gel system", "redGelSystem");
			AddPageResetButton(val2, "Reset this page to default", "resetRedGelSystem");
			gelProjectileSpeed = Slider(val2, "Gel projectile speed multiplier", "gelProjectileSpeedMultiplier", 0.1f, 5f, 1f, 2);
			gelCoveragePerDroplet = Slider(val2, "Enemy coverage per droplet (%)", "gelCoveragePerDroplet", 0.1f, 100f, 4f, 1);
			gelCoverageRequired = Slider(val2, "Enemy coverage required (%)", "gelCoverageRequired", 0f, 100f, 75f, 1);
			gelSpotSize = Slider(val2, "Terrain gel size (normal = 1)", "gelSpotSize", 0.1f, 5f, 1.25f, 2);
			stuckDamage = Slider(val2, "Primary stuck grenade damage", "stuckDamage", 0f, 20f, 4.5f, 2);
			greenStuckDamage = Slider(val2, "Green stuck grenade damage", "greenStuckDamage", 0f, 20f, 6f, 2);
			stuckExplosionSize = Slider(val2, "Stuck blast size (Rocket = 1)", "stuckExplosionSize", 0.1f, 5f, 1.3f, 2);
			stuckSelfDamage = Slider(val2, "Stuck self-damage (HP)", "stuckSelfDamage", 0f, 100f, 35f, 0);
			stuckKnockback = Slider(val2, "Stuck knockback (Rocket = 1)", "stuckKnockbackMultiplier", 0f, 5f, 1f, 2);
			stuckChainRadius = Slider(val2, "Stuck chain range mult.", "stuckChainRadiusMultiplier", 0f, 10f, 2f, 2);
			stuckChainPropagationSpeed = Slider(val2, "Chain speed (units/s)", "stuckChainPropagationSpeed", 1f, 200f, 50f, 1);
			enemyCarrierDirectDamage = new BoolField(val2, "Carrier takes direct damage", "enemyCarrierDirectDamage", false);
			timedFuseDetonatesStuck = new BoolField(val2, "Non-stuck nades detonate stuck", "timedFuseDetonatesStuck", false);
			terrainStuckDetonatesOnEnemyWalkover = new BoolField(val2, "Enemy walk triggers traps", "terrainStuckDetonatesOnEnemyWalkover", false);
			gelEnemyFireRadius = Slider(val2, "Enemy fire radius (blast = 1)", "gelEnemyFireRadius", 0f, 10f, 2.5f, 2);
			gelEnemyFireBaseDuration = Slider(val2, "Enemy fire base time (s)", "gelEnemyFireBaseDuration", 0f, 20f, 3f, 2);
			gelEnemyFireExtraDuration = Slider(val2, "Extra time per grenade (s)", "gelEnemyFireExtraDuration", 0f, 20f, 1f, 2);
			gelEnemyFireMaximumDuration = Slider(val2, "Enemy fire max time (s)", "gelEnemyFireMaximumDuration", 0f, 60f, 8f, 2);
			ConfigPanel val3 = new ConfigPanel(val2, "Red gel burst", "redGelBurst");
			AddPageResetButton(val3, "Reset this page to default", "resetRedGelBurst");
			redBurstDirectDamage = Slider(val3, "Direct hit damage", "redBurstDirectDamage", 0f, 20f, 2.5f, 2);
			redBurstTerrainDamage = Slider(val3, "Terrain-stuck grenade damage", "redBurstTerrainDamage", 0f, 20f, 3f, 2);
			redBurstEnemyDamage = Slider(val3, "Enemy-stuck grenade damage", "redBurstEnemyDamage", 0f, 20f, 2.5f, 2);
			redBurstAirshotDamage = Slider(val3, "Airshot damage", "redBurstAirshotDamage", 0f, 20f, 3.5f, 2);
			redBurstShotCount = Slider(val3, "Shot count", "redBurstShotCount", 1f, 10f, 3f, 0);
			redBurstDuration = Slider(val3, "Burst duration (seconds)", "redBurstDuration", 0f, 5f, 0.3f, 2);
			redBurstCooldown = Slider(val3, "Primary cooldown (seconds)", "redBurstCooldown", 0f, 30f, 4.5f, 2);
			redBurstKnockback = Slider(val3, "Blast knockback (Rocket = 1)", "redBurstKnockback", 0f, 5f, 0.4f, 2);
			ConfigPanel val4 = new ConfigPanel(configurator.rootPanel, "Blue slingshot point", "blueSlingshotPoint");
			AddPageResetButton(val4, "Reset this page to default", "resetBlueSlingshotPoint");
			blueDistance = Slider(val4, "Placement distance", "bluePlacementDistance", 5.5f, 200f, 20f, 1);
			blueCooldown = Slider(val4, "Cooldown (seconds)", "blueCooldown", 0.05f, 10f, 4f, 2);
			blueSlingshotForce = Slider(val4, "Extra slingshot force", "blueSlingshotForce", -50f, 200f, 0f, 1);
			bluePointSize = Slider(val4, "Hook point size multiplier", "bluePointSize", 0.25f, 4f, 1f, 2);
			blueMaximumHookPoints = Slider(val4, "Maximum created hook points", "blueMaximumHookPoints", 1f, 10f, 1f, 0);
			blueGreenHookPoints = Slider(val4, "Created green hook points", "blueGreenHookPoints", 0f, 10f, 0f, 0);
			blueRequireGroundAfterUse = new BoolField(val4, "Must land after hook use", "blueRequireGroundAfterUse", false);
			blueKnuckleblasterRefundsCooldown = new BoolField(val4, "Knuckleblast refunds cooldown", "blueKnuckleblasterRefundsCooldown", true);
			pinkArmingDelay = Slider(val4, "Pink first arm time (s)", "pinkArmingDelay", 0f, 30f, 2.25f, 2);
			pinkConductionArmingDelay = Slider(val4, "Pink re-arm time (s)", "pinkConductionArmingDelay", 0f, 30f, 3.5f, 2);
			pinkConductionRearmDelay = Slider(val4, "Pink re-arm after zap (s)", "pinkConductionRearmDelay", 0f, 30f, 5f, 2);
			pinkPullDelay = Slider(val4, "Pink pull delay (seconds)", "pinkPullDelay", 0f, 5f, 0.5f, 2);
			pinkPullRange = Slider(val4, "Pink pull range (units)", "pinkPullRange", 0f, 200f, 30f, 1);
			pinkPullSpeed = Slider(val4, "Pink pull speed (units/second)", "pinkPullSpeed", 0f, 200f, 50f, 1);
			blueReplacementDamage = Slider(val4, "Pink explosion damage", "blueReplacementDamage", 0f, 20f, 3.5f, 2);
			blueReplacementExplosionSize = Slider(val4, "Pink blast size (Providence = 1)", "blueReplacementExplosionSize", 0.1f, 5f, 1.2f, 2);
			blueReplacementForce = Slider(val4, "Pink enemy launch force", "blueReplacementForceRaw", 0f, 50000f, 20000f, 0);
			ConfigPanel val5 = new ConfigPanel(val4, "Pink blast enemy damage", "pinkBlastEnemyDamage");
			val5.headerText = "Extra damage percentage for pink explosion only. 100% = unchanged. Native explosive resistance remains active.";
			AddPageResetButton(val5, "Reset this page to default", "resetPinkBlastEnemyDamage");
			pinkBlastEnemyDamageMultipliers.Clear();
			foreach (EnemyType item in from EnemyType value in Enum.GetValues(typeof(EnemyType))
				orderby ((object)(*(EnemyType*)(&value))/*cast due to .constrained prefix*/).ToString()
				select value)
			{
				pinkBlastEnemyDamageMultipliers[item] = Slider(val5, FriendlyEnemyName(item) + " damage (%)", "pinkBlastDamage_" + ((object)(*(EnemyType*)(&item))/*cast due to .constrained prefix*/).ToString(), 0f, 500f, GetPinkBlastDefaultDamagePercent(item), 0);
			}
			ConfigPanel val6 = new ConfigPanel(configurator.rootPanel, "Style bonuses", "styleBonuses");
			AddPageResetButton(val6, "Reset this page to default", "resetStyleBonuses");
			pipeDreamDistance = Slider(val6, "PIPE DREAM minimum distance", "pipeDreamMinimumDistance", 1f, 250f, 56f, 1);
			moonShotDistance = Slider(val6, "MOON/OUT-SNIPED range", "moonShotMinimumDistance", 1f, 400f, 125f, 1);
			pipeDreamStylePoints = Slider(val6, "PIPE DREAM style points", "pipeDreamStylePoints", 0f, 10000f, 150f, 0);
			moonShotStylePoints = Slider(val6, "MOON SHOT style points", "moonShotStylePoints", 0f, 10000f, 550f, 0);
			outSnipedStylePoints = Slider(val6, "OUT-SNIPED style points", "outSnipedStylePoints", 0f, 10000f, 550f, 0);
			walkingBombStylePoints = Slider(val6, "WALKING BOMB style points", "walkingBombStylePoints", 0f, 5000f, 90f, 0);
			directHitStylePoints = Slider(val6, "Direct-hit base style points", "directHitStylePoints", 0f, 5000f, 35f, 0);
			pipeDreamDamageMultiplier = Slider(val6, "PIPE DREAM damage multiplier", "pipeDreamDamageMultiplier", 0f, 10f, 1f, 2);
			pipeDreamExplosionSizeMultiplier = Slider(val6, "PIPE DREAM blast mult.", "pipeDreamExplosionSizeMultiplier", 0.1f, 10f, 1f, 2);
			moonShotDamageMultiplier = Slider(val6, "MOON SHOT damage multiplier", "moonShotDamageMultiplier", 0f, 10f, 1.15f, 2);
			moonShotExplosionSizeMultiplier = Slider(val6, "MOON SHOT blast mult.", "moonShotExplosionSizeMultiplier", 0.1f, 10f, 1.15f, 2);
		}
	}
	[HarmonyPatch(typeof(Grenade), "Awake")]
	internal static class GrenadeAwakePatch
	{
		private static void Postfix(Grenade __instance)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if (!GrenadeSpawnContext.Active)
			{
				return;
			}
			if (GrenadeSpawnContext.Profile == GrenadeProjectileProfile.BlueDelivery)
			{
				if ((Object)(object)((Component)__instance).GetComponent<BlueHookDeliveryProjectile>() == (Object)null)
				{
					BlueHookDeliveryProjectile blueHookDeliveryProjectile = ((Component)__instance).gameObject.AddComponent<BlueHookDeliveryProjectile>();
					blueHookDeliveryProjectile.Grenade = __instance;
					blueHookDeliveryProjectile.Target = BlueHookDeliveryContext.Target;
				}
			}
			else if ((Object)(object)((Component)__instance).GetComponent<GrenadeLauncherProjectile>() == (Object)null)
			{
				GrenadeLauncherProjectile grenadeLauncherProjectile = ((Component)__instance).gameObject.AddComponent<GrenadeLauncherProjectile>();
				grenadeLauncherProjectile.Grenade = __instance;
				grenadeLauncherProjectile.Profile = GrenadeSpawnContext.Profile;
				WeaponVisualRuntime.AttachProjectileVisual(__instance, GrenadeSpawnContext.Profile);
			}
		}
	}
	[HarmonyPatch(typeof(Grenade), "FixedUpdate")]
	internal static class GrenadeFixedUpdatePatch
	{
		private static bool Prefix(Grenade __instance)
		{
			if ((Object)(object)((Component)__instance).GetComponent<GrenadeLauncherProjectile>() == (Object)null)
			{
				return (Object)(object)((Component)__instance).GetComponent<BlueHookDeliveryProjectile>() == (Object)null;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(CustomGravity), "FixedUpdate")]
	internal static class GrenadeCustomGravityPatch
	{
		private static bool Prefix(CustomGravity __instance)
		{
			if ((Object)(object)((Component)__instance).GetComponent<GrenadeLauncherProjectile>() == (Object)null)
			{
				return (Object)(object)((Component)__instance).GetComponent<BlueHookDeliveryProjectile>() == (Object)null;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Grenade), "Start")]
	internal static class GrenadeStartPatch
	{
		private static void Postfix(Grenade __instance)
		{
			((Component)__instance).GetComponent<GrenadeLauncherProjectile>()?.Launch();
			((Component)__instance).GetComponent<BlueHookDeliveryProjectile>()?.Launch();
		}
	}
	[HarmonyPatch(typeof(Grenade), "OnCollisionEnter")]
	internal static class GrenadeOnCollisionEnterPatch
	{
		private static bool Prefix(Grenade __instance, Collision collision)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)((Component)__instance).GetComponent<BlueHookDeliveryProjectile>() != (Object)null)
			{
				return false;
			}
			if (collision != null && (Object)(object)collision.collider != (Object)null && (Object)(object)((Component)collision.collider).GetComponentInParent<PinkHookPointMarker>() != (Object)null)
			{
				return false;
			}
			GrenadeLauncherProjectile component = ((Component)__instance).GetComponent<GrenadeLauncherProjectile>();
			if ((Object)(object)component == (Object)null)
			{
				return true;
			}
			ContactPoint val = (ContactPoint)((collision.contactCount > 0) ? collision.GetContact(0) : default(ContactPoint));
			Vector3 collisionNormal = ((collision.contactCount > 0) ? ((ContactPoint)(ref val)).normal : Vector3.zero);
			Vector3 collisionPoint = ((collision.contactCount > 0) ? ((ContactPoint)(ref val)).point : ((Component)__instance).transform.position);
			component.HandleCollision(collision.collider, -collision.relativeVelocity, collisionNormal, collisionPoint);
			return false;
		}
	}
	[HarmonyPatch(typeof(Grenade), "Collision", new Type[]
	{
		typeof(Collider),
		typeof(Vector3)
	})]
	internal static class GrenadeCollisionPatch
	{
		private static bool Prefix(Grenade __instance, Collider other, Vector3 velocity)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)((Component)__instance).GetComponent<BlueHookDeliveryProjectile>() != (Object)null)
			{
				return false;
			}
			if ((Object)(object)other != (Object)null && (Object)(object)((Component)other).GetComponentInParent<PinkHookPointMarker>() != (Object)null)
			{
				return false;
			}
			GrenadeLauncherProjectile component = ((Component)__instance).GetComponent<GrenadeLauncherProjectile>();
			if ((Object)(object)component == (Object)null)
			{
				return true;
			}
			component.HandleCollision(other, velocity, Vector3.zero, ((Component)__instance).transform.position);
			return false;
		}
	}
	[HarmonyPatch(typeof(Grenade), "OnTriggerEnter")]
	internal static class PinkHookGrenadeTriggerIgnorePatch
	{
		private static bool Prefix(Collider other)
		{
			if (!((Object)(object)other == (Object)null))
			{
				return (Object)(object)((Component)other).GetComponentInParent<PinkHookPointMarker>() == (Object)null;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Explosion), "Collide")]
	internal static class GrenadeLauncherExplosionPatch
	{
		private struct State
		{
			internal bool ChangedMultiplier;

			internal float EnemyDamageMultiplier;

			internal bool ChangedDamage;

			internal int Damage;

			internal GrenadeLauncherExplosionMarker Marker;

			internal EnemyIdentifier Enemy;

			internal bool ReplacesDirectHitBaseStyle;
		}

		private static bool Prefix(Explosion __instance, Collider other, out State __state)
		{
			//IL_0179: 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_0152: Invalid comparison between Unknown and I4
			__state = default(State);
			GrenadeLauncherExplosionMarker grenadeLauncherExplosionMarker = GrenadeLauncherExplosionMarker.TryGet(__instance);
			GrenadeLauncherProjectile grenadeLauncherProjectile = GrenadeLauncherProjectile.TryGetStuckProjectile(other);
			if ((Object)(object)grenadeLauncherProjectile != (Object)null && grenadeLauncherProjectile.IsStuck)
			{
				if ((Object)(object)grenadeLauncherExplosionMarker != (Object)null && (grenadeLauncherExplosionMarker.Mode == GrenadeExplosionMode.Surface || grenadeLauncherExplosionMarker.Mode == GrenadeExplosionMode.GreenSurface) && !PluginSettings.TimedFuseDetonatesStuck)
				{
					return false;
				}
				if (IsPlayerExplosion(__instance))
				{
					grenadeLauncherProjectile.DetonateStuck();
				}
				return false;
			}
			if ((Object)(object)grenadeLauncherExplosionMarker == (Object)null)
			{
				return true;
			}
			if (grenadeLauncherExplosionMarker.BlueHookReplacement)
			{
				if ((Object)(object)other != (Object)null && ((Component)other).CompareTag("Player"))
				{
					return false;
				}
				return (Object)(object)GrenadeLauncherProjectile.TryGetLivingEnemy(other) == (Object)null;
			}
			EnemyIdentifier val = GrenadeLauncherProjectile.TryGetLivingEnemy(other);
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			__state.Marker = grenadeLauncherExplosionMarker;
			__state.Enemy = val;
			__state.ReplacesDirectHitBaseStyle = grenadeLauncherExplosionMarker.DirectEnemyId == ((Object)val).GetInstanceID() && !grenadeLauncherExplosionMarker.Parried && (grenadeLauncherExplosionMarker.Mode == GrenadeExplosionMode.Direct || grenadeLauncherExplosionMarker.Mode == GrenadeExplosionMode.GreenDirect);
			if (__state.ReplacesDirectHitBaseStyle)
			{
				GrenadeDirectHitStyleContext.Enter();
			}
			if (PluginSettings.EnemyCarrierTakesDirectDamage && grenadeLauncherExplosionMarker.StuckHostEnemyId != 0 && ((Object)val).GetInstanceID() == grenadeLauncherExplosionMarker.StuckHostEnemyId)
			{
				__state.ChangedDamage = true;
				__state.Damage = __instance.damage;
				__instance.damage = Mathf.RoundToInt(Mathf.Max(0f, grenadeLauncherExplosionMarker.StuckCarrierDamage) * 10f);
			}
			if (grenadeLauncherExplosionMarker.Parried && (int)val.enemyType == 4)
			{
				grenadeLauncherExplosionMarker.DamageBlockedEnemy(val, other);
				return false;
			}
			__state.ChangedMultiplier = true;
			__state.EnemyDamageMultiplier = __instance.enemyDamageMultiplier;
			__instance.enemyDamageMultiplier *= PluginSettings.GetEnemyDamageMultiplier(val.enemyType);
			return true;
		}

		private static bool IsPlayerExplosion(Explosion explosion)
		{
			if ((Object)(object)explosion == (Object)null || explosion.enemy)
			{
				return false;
			}
			if ((Object)(object)StuckDetonationContext.Current != (Object)null && StuckDetonationContext.CanCurrentBeamDetonate)
			{
				return true;
			}
			if ((Object)(object)explosion.sourceWeapon == (Object)null)
			{
				return false;
			}
			GameObject sourceWeapon = explosion.sourceWeapon;
			NewMovement instance = MonoSingleton<NewMovement>.Instance;
			if (!((Object)(object)instance != (Object)null) || (!((Object)(object)sourceWeapon == (Object)(object)((Component)instance).gameObject) && !sourceWeapon.transform.IsChildOf(((Component)instance).transform)))
			{
				return (Object)(object)sourceWeapon.GetComponentInParent<NewMovement>() != (Object)null;
			}
			return true;
		}

		private static Exception Finalizer(Explosion __instance, State __state, Exception __exception)
		{
			if (__state.ReplacesDirectHitBaseStyle)
			{
				GrenadeDirectHitStyleContext.Exit();
			}
			if (__state.ChangedMultiplier)
			{
				__instance.enemyDamageMultiplier = __state.EnemyDamageMultiplier;
			}
			if (__state.ChangedDamage)
			{
				__instance.damage = __state.Damage;
			}
			if (__exception == null && (Object)(object)__state.Marker != (Object)null && (Object)(object)__state.Enemy != (Object)null)
			{
				__state.Marker.TryAwardLongRangeStyle(__state.Enemy);
				__state.Marker.TryAwardWalkingBomb(__state.Enemy);
			}
			return __exception;
		}
	}
	internal static class GrenadeDirectHitStyleContext
	{
		private static int depth;

		internal static bool Active => depth > 0;

		internal static void Enter()
		{
			depth++;
		}

		internal static void Exit()
		{
			depth = Math.Max(0, depth - 1);
		}
	}
	[HarmonyPatch(typeof(StyleCalculator), "AddPoints")]
	internal static class GrenadeDirectHitBaseStylePatch
	{
		private static void Prefix(ref int points, string pointName)
		{
			if (GrenadeDirectHitStyleContext.Active && pointName == "ultrakill.explosionhit")
			{
				points = PluginSettings.DirectHitStylePoints;
			}
		}
	}
	internal sealed class GrenadeLauncherBlueShockwaveMarker : MonoBehaviour
	{
	}
	internal static class GrenadeLauncherBlueShockwaveContext
	{
		private static int depth;

		internal static bool Active => depth > 0;

		internal static void Enter()
		{
			depth++;
		}

		internal static void Exit()
		{
			if (depth > 0)
			{
				depth--;
			}
		}
	}
	[HarmonyPatch(typeof(PhysicalShockwave), "CheckCollision")]
	internal static class GrenadeLauncherPhysicalShockwavePatch
	{
		private static bool Prefix(PhysicalShockwave __instance, out bool __state)
		{
			__state = (Object)(object)__instance != (Object)null && (Object)(object)((Component)__instance).GetComponentInParent<GrenadeLauncherBlueShockwaveMarker>() != (Object)null;
			return !__state;
		}

		private static Exception Finalizer(bool __state, Exception __exception)
		{
			return __exception;
		}
	}
	[HarmonyPatch(typeof(Enemy), "HandleBloodSelection")]
	internal static class GrenadeLauncherBloodSelectionPatch
	{
		private static bool Prefix(ref GameObject __result)
		{
			if (!GrenadeLauncherBlueShockwaveContext.Active)
			{
				return true;
			}
			__result = null;
			return false;
		}
	}
	[HarmonyPatch(typeof(Enemy), "ProcessBloodEffects")]
	internal static class GrenadeLauncherBloodEffectsPatch
	{
		private static bool Prefix()
		{
			return !GrenadeLauncherBlueShockwaveContext.Active;
		}
	}
	[HarmonyPatch(typeof(Enemy), "PlayHurtSound")]
	internal static class GrenadeLauncherHurtSoundPatch
	{
		private static bool Prefix()
		{
			return !GrenadeLauncherBlueShockwaveContext.Active;
		}
	}
	[HarmonyPatch(typeof(Enemy), "BloodExplosion")]
	internal static class GrenadeLauncherBloodExplosionPatch
	{
		private static bool Prefix()
		{
			return !GrenadeLauncherBlueShockwaveContext.Active;
		}
	}
	[HarmonyPatch(typeof(BloodsplatterManager), "PlayBloodSound")]
	internal static class GrenadeLauncherBloodSoundPatch
	{
		private static bool Prefix()
		{
			return !GrenadeLauncherBlueShockwaveContext.Active;
		}
	}
	internal enum GrenadeExplosionMode
	{
		Direct,
		Surface,
		Parried,
		GreenDirect,
		GreenSurface,
		Stuck
	}
	internal enum GrenadeLongRangeStyle
	{
		None,
		PipeDream,
		MoonShot
	}
	internal static class GrenadeStyleAwards
	{
		private const string PipeDreamId = "grenadelauncher.pipe_dream";

		private const string MoonShotId = "grenadelauncher.moon_shot";

		private const string OutSnipedId = "grenadelauncher.out_sniped";

		private const string WalkingBombId = "grenadelauncher.walking_bomb";

		private static StyleHUD registeredHud;

		private static readonly HashSet<int> walkingBombAwardedChains = new HashSet<int>();

		internal static void Award(GrenadeLongRangeStyle style, EnemyIdentifier enemy, GameObject sourceWeapon)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			StyleHUD val = EnsureRegistered(enemy);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			int num;
			object obj;
			if (style == GrenadeLongRangeStyle.MoonShot && (int)enemy.enemyType == 20)
			{
				num = (enemy.dead ? 1 : 0);
				if (num != 0)
				{
					obj = "grenadelauncher.out_sniped";
					goto IL_0042;
				}
			}
			else
			{
				num = 0;
			}
			obj = ((style == GrenadeLongRangeStyle.MoonShot) ? "grenadelauncher.moon_shot" : "grenadelauncher.pipe_dream");
			goto IL_0042;
			IL_0042:
			string text = (string)obj;
			int num2 = ((num != 0) ? PluginSettings.OutSnipedStylePoints : ((style == GrenadeLongRangeStyle.MoonShot) ? PluginSettings.MoonShotStylePoints : PluginSettings.PipeDreamStylePoints));
			val.AddPoints(num2, text, sourceWeapon, enemy, -1, "", "");
		}

		internal static void AwardWalkingBomb(int chainId, EnemyIdentifier enemy, GameObject sourceWeapon)
		{
			if (chainId > 0 && walkingBombAwardedChains.Add(chainId))
			{
				StyleHUD val = EnsureRegistered(enemy);
				if ((Object)(object)val != (Object)null)
				{
					val.AddPoints(PluginSettings.WalkingBombStylePoints, "grenadelauncher.walking_bomb", sourceWeapon, enemy, -1, "", "");
				}
			}
		}

		internal static void ResetWalkingBombChains()
		{
			walkingBombAwardedChains.Clear();
		}

		private static StyleHUD EnsureRegistered(EnemyIdentifier enemy)
		{
			StyleHUD instance = MonoSingleton<StyleHUD>.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)enemy == (Object)null)
			{
				return null;
			}
			if ((Object)(object)registeredHud != (Object)(object)instance)
			{
				instance.RegisterStyleItem("grenadelauncher.pipe_dream", "<color=#00ffffff>PIPE DREAM</color>");
				instance.RegisterStyleItem("grenadelauncher.moon_shot", "<color=#FFD700>MOON SHOT</color>");
				instance.RegisterStyleItem("grenadelauncher.out_sniped", "<color=#FFD700>OUT-SNIPED</color>");
				instance.RegisterStyleItem("grenadelauncher.walking_bomb", "<color=#00ffffff>WALKING BOMB</color>");
				registeredHud = instance;
			}
			return instance;
		}
	}
	internal sealed class GrenadeLauncherExplosionMarker : MonoBehaviour
	{
		private static readonly Dictionary<int, GrenadeLauncherExplosionMarker> ActiveRoots = new Dictionary<int, GrenadeLauncherExplosionMarker>();

		private readonly HashSet<int> manuallyDamagedEnemies = new HashSet<int>();

		private readonly HashSet<int> styleAwardedEnemies = new HashSet<int>();

		private bool walkingBombAwarded;

		internal bool Parried;

		internal GrenadeExplosionMode Mode;

		internal float Damage;

		internal GameObject SourceWeapon;

		internal int DirectEnemyId;

		internal GrenadeLongRangeStyle LongRangeStyle;

		internal int StuckHostEnemyId;

		internal float StuckCarrierDamage;

		internal int StuckChainGroupId;

		internal GrenadeProjectileProfile DirectProfile;

		internal float DirectPlanarDistance;

		internal float DirectStraightDistance;

		internal float TheoreticalSameHeightRange;

		internal float LaunchElevationDegrees;

		internal float ConfiguredStyleThreshold;

		internal bool Airshot;

		internal bool BlueHookReplacement;

		private int rootId;

		private void Awake()
		{
			rootId = (((Object)(object)((Component)this).transform.root != (Object)null) ? ((Object)((Component)this).transform.root).GetInstanceID() : ((Object)((Component)this).gameObject).GetInstanceID());
			ActiveRoots[rootId] = this;
		}

		private void OnDestroy()
		{
			if (rootId != 0 && ActiveRoots.TryGetValue(rootId, out var value) && (Object)(object)value == (Object)(object)this)
			{
				ActiveRoots.Remove(rootId);
			}
		}

		internal static GrenadeLauncherExplosionMarker TryGet(Explosion explosion)
		{
			if ((Object)(object)explosion == (Object)null)
			{
				return null;
			}
			int key = (((Object)(object)((Component)explosion).transform.root != (Object)null) ? ((Object)((Component)explosion).transform.root).GetInstanceID() : ((Object