Decompiled source of Grenade Launcher v1.0.2

BepInEx\plugins\DocValentyne-GrenadeLauncher\GrenadeLauncher.dll

Decompiled a day 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.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PluginConfig.API;
using PluginConfig.API.Decorators;
using PluginConfig.API.Fields;
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("1.0.2.0")]
[assembly: AssemblyInformationalVersion("1.0.2+4cb420845310a5af127943c5c300f3a8f26a3252")]
[assembly: AssemblyProduct("GrenadeLauncher")]
[assembly: AssemblyTitle("GrenadeLauncher")]
[assembly: AssemblyVersion("1.0.2.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", "1.0.2")]
	[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 = "1.0.2";

		private readonly Dictionary<int, ConfigEntry<bool>> slotLoadouts = new Dictionary<int, ConfigEntry<bool>>();

		private readonly Dictionary<string, ConfigEntry<bool>> variantLoadouts = new Dictionary<string, ConfigEntry<bool>>();

		private readonly Dictionary<int, ConfigEntry<bool>> variantMigrations = new Dictionary<int, ConfigEntry<bool>>();

		private Harmony harmony;

		private GameObject runtimeHost;

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource LogSource { get; private set; }

		internal bool GrenadeModeEnabled
		{
			get
			{
				return GetSlotEntry(GameProgressSaver.currentSlot).Value;
			}
			set
			{
				GetSlotEntry(GameProgressSaver.currentSlot).Value = value;
				((BaseUnityPlugin)this).Config.Save();
				TerminalIntegration.RefreshAll();
			}
		}

		internal bool AnyGrenadeModeEnabled
		{
			get
			{
				int slot = Math.Max(0, GameProgressSaver.currentSlot);
				if (!GetVariantMigrationEntry(slot).Value)
				{
					return GetSlotEntry(slot).Value;
				}
				if (!GetVariantEntry(slot, 0).Value && !GetVariantEntry(slot, 1).Value)
				{
					return GetVariantEntry(slot, 2).Value;
				}
				return true;
			}
		}

		internal bool IsGrenadeModeEnabled(int variation)
		{
			if (variation < 0 || variation > 2)
			{
				return false;
			}
			int slot = Math.Max(0, GameProgressSaver.currentSlot);
			if (!GetVariantMigrationEntry(slot).Value)
			{
				return GetSlotEntry(slot).Value;
			}
			return GetVariantEntry(slot, variation).Value;
		}

		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();
				GetVariantEntry(slot, variation).Value = enabled;
				((BaseUnityPlugin)this).Config.Save();
			}
		}

		internal void EnsureVariantMigration()
		{
			int slot = Math.Max(0, GameProgressSaver.currentSlot);
			ConfigEntry<bool> variantMigrationEntry = GetVariantMigrationEntry(slot);
			if (!variantMigrationEntry.Value)
			{
				bool value = GetSlotEntry(slot).Value;
				for (int i = 0; i < 3; i++)
				{
					GetVariantEntry(slot, i).Value = value;
				}
				variantMigrationEntry.Value = true;
				((BaseUnityPlugin)this).Config.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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			Instance = this;
			LogSource = ((BaseUnityPlugin)this).Logger;
			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>();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Grenade Launcher v1.0.2 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 ConfigEntry<bool> GetSlotEntry(int slot)
		{
			if (slot < 0)
			{
				slot = 0;
			}
			if (!slotLoadouts.TryGetValue(slot, out var value))
			{
				value = ((BaseUnityPlugin)this).Config.Bind<bool>("Loadout", "SaveSlot" + slot + "UsesGrenadeLauncher", false, "Equip Grenade Launcher primary fire for all three Rocket Launcher variants in this save slot.");
				slotLoadouts.Add(slot, value);
			}
			return value;
		}

		private ConfigEntry<bool> GetVariantEntry(int slot, int variation)
		{
			string key = slot + ":" + variation;
			if (!variantLoadouts.TryGetValue(key, out var value))
			{
				value = ((BaseUnityPlugin)this).Config.Bind<bool>("Loadout", "SaveSlot" + slot + "RocketVariant" + variation + "UsesGrenadeLauncher", false, "Use the alternate Grenade Launcher form for this Rocket Launcher variant.");
				variantLoadouts.Add(key, value);
			}
			return value;
		}

		private ConfigEntry<bool> GetVariantMigrationEntry(int slot)
		{
			if (!variantMigrations.TryGetValue(slot, out var value))
			{
				value = ((BaseUnityPlugin)this).Config.Bind<bool>("Loadout", "SaveSlot" + slot + "PerVariantLoadoutMigrated", false, "Whether the old all-rocket setting has been copied to the native per-variant terminal controls.");
				variantMigrations.Add(slot, value);
			}
			return value;
		}
	}
	[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,
		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 SharedRocketFireCooldown
	{
		private static float readyAt;

		internal static bool Ready
		{
			get
			{
				if (!CooldownRules.NoWeaponCooldown)
				{
					return Time.time >= readyAt;
				}
				return true;
			}
		}

		internal static void Mark(float duration)
		{
			if (!CooldownRules.NoWeaponCooldown)
			{
				readyAt = Mathf.Max(readyAt, Time.time + Mathf.Max(0.05f, duration));
			}
		}

		internal static void Reset()
		{
			readyAt = 0f;
		}
	}
	internal static class CooldownRules
	{
		internal static bool NoWeaponCooldown => NoWeaponCooldown.NoCooldown;
	}
	[HarmonyPatch(typeof(RocketLauncher), "Shoot")]
	internal static class RocketLauncherShootPatch
	{
		private struct State
		{
			internal bool Active;

			internal bool EnteredContext;

			internal bool Executed;

			internal bool SharedEnforced;

			internal bool NotifyGreenPrimary;

			internal bool NotifyBluePrimary;

			internal float RateOfFire;

			internal float SharedInterval;
		}

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

		private static bool Prefix(RocketLauncher __instance, out State __state)
		{
			bool flag = (Object)(object)Plugin.Instance != (Object)null && Plugin.Instance.IsGrenadeModeEnabled(__instance);
			bool flag2 = (Object)(object)Plugin.Instance != (Object)null && Plugin.Instance.AnyGrenadeModeEnabled;
			WeaponIdentifier val = WeaponId.Invoke(__instance);
			bool flag3 = (Object)(object)val != (Object)null && val.duplicate;
			__state = new State
			{
				Active = flag,
				SharedEnforced = (flag2 && !flag3),
				RateOfFire = __instance.rateOfFire,
				SharedInterval = (flag ? PluginSettings.FireInterval : __instance.rateOfFire)
			};
			if (__state.SharedEnforced && !SharedRocketFireCooldown.Ready)
			{
				return false;
			}
			__state.Executed = true;
			if (!__state.Active)
			{
				return 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 (__exception == null && __state.Executed && __state.SharedEnforced)
			{
				SharedRocketFireCooldown.Mark(__state.SharedInterval);
			}
			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(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 ArcCurrent = "Current snappier arc";

		internal const string ArcCustom = "Custom gravity";

		private static StringListField arcPreset;

		private static FloatSliderField damage;

		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 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 BoolField eyeHeightScaling;

		private static FloatSliderField fallbackEyeHeight;

		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,
				120f
			},
			{
				(EnemyType)33,
				110f
			},
			{
				(EnemyType)2,
				85f
			},
			{
				(EnemyType)4,
				100f
			},
			{
				(EnemyType)31,
				200f
			},
			{
				(EnemyType)38,
				175f
			},
			{
				(EnemyType)14,
				125f
			}
		};

		private static FloatSliderField greenCooldown;

		private static FloatSliderField greenSpeed;

		private static FloatSliderField greenUpwardVelocity;

		private static FloatSliderField greenGravity;

		private static FloatSliderField greenDirectDamage;

		private static FloatSliderField greenSurfaceDamage;

		private static FloatSliderField greenDirectExplosionSize;

		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 FloatSliderField blueDistance;

		private static FloatSliderField blueCooldown;

		private static FloatSliderField blueSlingshotForce;

		private static FloatSliderField bluePointSize;

		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 pipeDreamDamageMultiplier;

		private static FloatSliderField pipeDreamExplosionSizeMultiplier;

		private static FloatSliderField moonShotDamageMultiplier;

		private static FloatSliderField moonShotExplosionSizeMultiplier;

		private static BoolField rangeTelemetry;

		internal static float Damage
		{
			get
			{
				FloatSliderField obj = damage;
				if (obj == null)
				{
					return 4f;
				}
				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 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 2.5f;
				}
				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 bool EyeHeightScaling
		{
			get
			{
				BoolField obj = eyeHeightScaling;
				if (obj == null)
				{
					return true;
				}
				return obj.value;
			}
		}

		internal static float FallbackEyeHeight
		{
			get
			{
				FloatSliderField obj = fallbackEyeHeight;
				if (obj == null)
				{
					return 2.9f;
				}
				return obj.value;
			}
		}

		internal static float GravityMultiplier
		{
			get
			{
				StringListField obj = arcPreset;
				string text = ((obj != null) ? obj.value : null) ?? "Original TF2-scaled arc";
				if (text == "Original TF2-scaled arc")
				{
					return 1f;
				}
				if (text == "Current snappier arc")
				{
					return 2f;
				}
				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 GreenSurfaceDamage
		{
			get
			{
				FloatSliderField obj = greenSurfaceDamage;
				if (obj == null)
				{
					return 4f;
				}
				return obj.value;
			}
		}

		internal static float GreenDirectExplosionSize
		{
			get
			{
				FloatSliderField obj = greenDirectExplosionSize;
				if (obj == null)
				{
					return 1.4f;
				}
				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 4f;
				}
				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 45f;
				}
				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 true;
				}
				return obj.value;
			}
		}

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

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

		internal static float BlueCooldown
		{
			get
			{
				FloatSliderField obj = blueCooldown;
				if (obj == null)
				{
					return 7f;
				}
				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 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 : 100f);
			}
		}

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

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

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

		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 bool RangeTelemetryEnabled
		{
			get
			{
				BoolField obj = rangeTelemetry;
				if (obj == null)
				{
					return false;
				}
				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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			//IL_0315: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Expected O, but got Unknown
			//IL_0331: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Expected O, but got Unknown
			//IL_035a: Expected O, but got Unknown
			//IL_0375: Unknown result type (might be due to invalid IL or missing references)
			//IL_037b: Expected O, but got Unknown
			//IL_03d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03de: Unknown result type (might be due to invalid IL or missing references)
			//IL_0414: 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, "Get comfortable with the weapon before changing its settings.", 24);
			arcPreset = new StringListField(val.rootPanel, "Arc preset", "arcPreset", new string[3] { "Current snappier arc", "Original TF2-scaled arc", "Custom gravity" }, "Original TF2-scaled arc");
			damage = Slider(val, "Damage", "damage", 0f, 10f, 4f, 2);
			MigrateDamageDefault();
			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, "Explosion knockback (rocket = 1)", "knockbackMultiplier", 0f, 3f, 1f, 2);
			lifetime = Slider(val, "Silent projectile lifetime", "projectileLifetime", 1f, 60f, 15f, 1);
			surfaceFuse = Slider(val, "Surface fuse (seconds)", "surfaceFuse", 0.1f, 10f, 1f, 2);
			hookFuseGrace = Slider(val, "Fuse time added per Whiplash hook (seconds)", "hookFuseGrace", 0f, 2f, 0.1f, 2);
			surfaceDamage = Slider(val, "Surface detonation damage", "surfaceDamage", 0f, 10f, 2.5f, 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 explosion size (rocket = 1)", "parryExplosionSize", 0.25f, 5f, 1f, 2);
			parrySpeed = Slider(val, "Parried projectile speed multiplier", "parrySpeedMultiplier", 0.1f, 5f, 3f, 2);
			directSelfDamage = Slider(val, "Direct explosion self damage (HP)", "directSelfDamage", 0f, 100f, 35f, 0);
			surfaceSelfDamage = Slider(val, "Timed explosion self damage (HP)", "surfaceSelfDamage", 0f, 100f, 25f, 0);
			parrySelfDamage = Slider(val, "Parried explosion self damage (HP)", "parrySelfDamage", 0f, 100f, 30f, 0);
			ConfigPanel val2 = new ConfigPanel(val.rootPanel, "Debug / trajectory calibration", "debugTrajectoryCalibration")
			{
				headerText = "Only change these when diagnosing trajectory calibration."
			};
			eyeHeightScaling = new BoolField(val2, "Use eye-height calibration", "eyeHeightScaling", true);
			fallbackEyeHeight = Slider(val2, "Fallback V1 eye height", "fallbackEyeHeight", 0.5f, 10f, 2.9f, 2);
			InitializeAlternateSettings(val);
			ConfigPanel val3 = new ConfigPanel(val.rootPanel, "Enemy grenade damage", "enemyDamageMultipliers");
			val3.headerText = "Damage percentage is applied after ULTRAKILL's normal explosive weakness or resistance.";
			enemyDamageMultipliers.Clear();
			foreach (EnemyType item in from EnemyType val4 in Enum.GetValues(typeof(EnemyType))
				orderby ((object)(*(EnemyType*)(&val4))/*cast due to .constrained prefix*/).ToString()
				select val4)
			{
				enemyDamageMultipliers[item] = Slider(val3, FriendlyEnemyName(item) + " damage (%)", "enemyDamage_" + ((object)(*(EnemyType*)(&item))/*cast due to .constrained prefix*/).ToString(), 0f, 500f, releaseEnemyDamageDefaults.TryGetValue(item, out var value) ? value : 100f, 0);
			}
		}

		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 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 MigrateDamageDefault()
		{
			ConfigEntry<int> val = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<int>("Migration", "DefaultsVersion", 0, "Internal version used to apply changed defaults once without overwriting later customization.");
			if (val.Value < 1)
			{
				if (Mathf.Approximately(damage.value, 3f))
				{
					damage.value = 4f;
				}
				val.Value = 1;
				((BaseUnityPlugin)Plugin.Instance).Config.Save();
			}
		}

		private 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_0035: Expected O, but got Unknown
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Expected O, but got Unknown
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Expected O, but got Unknown
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Expected O, but got Unknown
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Expected O, but got Unknown
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Expected O, but got Unknown
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Expected O, but got Unknown
			//IL_01cb: Expected O, but got Unknown
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Expected O, but got Unknown
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Expected O, but got Unknown
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Expected O, but got Unknown
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Expected O, but got Unknown
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Expected O, but got Unknown
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Expected O, but got Unknown
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Expected O, but got Unknown
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0308: Expected O, but got Unknown
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_032d: Expected O, but got Unknown
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_0352: Expected O, but got Unknown
			//IL_0357: Unknown result type (might be due to invalid IL or missing references)
			//IL_0377: Expected O, but got Unknown
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_038d: Expected O, but got Unknown
			//IL_0388: Unknown result type (might be due to invalid IL or missing references)
			//IL_0392: Expected O, but got Unknown
			//IL_03a2: Expected O, but got Unknown
			//IL_039d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a7: Expected O, but got Unknown
			//IL_03b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dc: Expected O, but got Unknown
			//IL_03e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0401: Expected O, but got Unknown
			//IL_0406: Unknown result type (might be due to invalid IL or missing references)
			//IL_0426: Expected O, but got Unknown
			//IL_044a: Expected O, but got Unknown
			//IL_045f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0464: Unknown result type (might be due to invalid IL or missing references)
			//IL_0484: Expected O, but got Unknown
			//IL_0489: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a9: Expected O, but got Unknown
			//IL_04ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ce: Expected O, but got Unknown
			//IL_04d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f3: Expected O, but got Unknown
			//IL_04f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0518: Expected O, but got Unknown
			//IL_051d: Unknown result type (might be due to invalid IL or missing references)
			//IL_053d: Expected O, but got Unknown
			//IL_0542: Unknown result type (might be due to invalid IL or missing references)
			//IL_0562: Expected O, but got Unknown
			//IL_0567: Unknown result type (might be due to invalid IL or missing references)
			//IL_0587: Expected O, but got Unknown
			//IL_058c: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ac: Expected O, but got Unknown
			//IL_05d0: Expected O, but got Unknown
			//IL_05e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0605: Expected O, but got Unknown
			//IL_0600: Unknown result type (might be due to invalid IL or missing references)
			//IL_060a: Expected O, but got Unknown
			ConfigPanel val = new ConfigPanel(configurator.rootPanel, "Green contact grenade", "greenContactGrenade");
			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);
			greenSurfaceDamage = Slider(val, "Surface contact damage", "greenSurfaceDamage", 0f, 20f, 4f, 2);
			greenDirectExplosionSize = Slider(val, "Direct explosion size (rocket = 1)", "greenDirectExplosionSize", 0.1f, 5f, 1.4f, 2);
			greenSurfaceExplosionSize = Slider(val, "Surface explosion 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, "Explosion 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");
			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, 4f, 2);
			greenStuckDamage = Slider(val2, "Green stuck grenade damage", "greenStuckDamage", 0f, 20f, 6f, 2);
			stuckExplosionSize = Slider(val2, "Stuck explosion size (rocket = 1)", "stuckExplosionSize", 0.1f, 5f, 1.3f, 2);
			stuckSelfDamage = Slider(val2, "Stuck explosion self damage (HP)", "stuckSelfDamage", 0f, 100f, 45f, 0);
			stuckKnockback = Slider(val2, "Stuck explosion knockback (rocket = 1)", "stuckKnockbackMultiplier", 0f, 5f, 1f, 2);
			stuckChainRadius = Slider(val2, "Stuck grenade chain radius multiplier", "stuckChainRadiusMultiplier", 0f, 10f, 2f, 2);
			stuckChainPropagationSpeed = Slider(val2, "Chain propagation speed (units/second)", "stuckChainPropagationSpeed", 1f, 200f, 50f, 1);
			enemyCarrierDirectDamage = new BoolField(val2, "Enemy carrier takes direct-hit damage", "enemyCarrierDirectDamage", true);
			timedFuseDetonatesStuck = new BoolField(val2, "Timed-fuse explosions detonate stuck grenades", "timedFuseDetonatesStuck", false);
			ConfigPanel val3 = new ConfigPanel(configurator.rootPanel, "Blue slingshot point", "blueSlingshotPoint");
			blueDistance = Slider(val3, "Placement distance", "bluePlacementDistance", 5.5f, 200f, 27f, 1);
			blueCooldown = Slider(val3, "Cooldown (seconds)", "blueCooldown", 0.05f, 10f, 7f, 2);
			blueSlingshotForce = Slider(val3, "Extra slingshot force", "blueSlingshotForce", -50f, 200f, 0f, 1);
			bluePointSize = Slider(val3, "Hook point size multiplier", "bluePointSize", 0.25f, 4f, 1f, 2);
			ConfigPanel val4 = new ConfigPanel(configurator.rootPanel, "Style bonuses", "styleBonuses");
			pipeDreamDistance = Slider(val4, "PIPE DREAM minimum distance", "pipeDreamMinimumDistance", 1f, 250f, 56f, 1);
			moonShotDistance = Slider(val4, "MOON SHOT / OUT-SNIPED minimum distance", "moonShotMinimumDistance", 1f, 400f, 125f, 1);
			pipeDreamStylePoints = Slider(val4, "PIPE DREAM style points", "pipeDreamStylePoints", 0f, 5000f, 100f, 0);
			moonShotStylePoints = Slider(val4, "MOON SHOT style points", "moonShotStylePoints", 0f, 5000f, 500f, 0);
			outSnipedStylePoints = Slider(val4, "OUT-SNIPED style points", "outSnipedStylePoints", 0f, 5000f, 500f, 0);
			walkingBombStylePoints = Slider(val4, "WALKING BOMB style points", "walkingBombStylePoints", 0f, 5000f, 90f, 0);
			pipeDreamDamageMultiplier = Slider(val4, "PIPE DREAM damage multiplier", "pipeDreamDamageMultiplier", 0f, 10f, 1f, 2);
			pipeDreamExplosionSizeMultiplier = Slider(val4, "PIPE DREAM explosion size multiplier", "pipeDreamExplosionSizeMultiplier", 0.1f, 10f, 1f, 2);
			moonShotDamageMultiplier = Slider(val4, "MOON SHOT damage multiplier", "moonShotDamageMultiplier", 0f, 10f, 1.15f, 2);
			moonShotExplosionSizeMultiplier = Slider(val4, "MOON SHOT explosion size multiplier", "moonShotExplosionSizeMultiplier", 0.1f, 10f, 1.15f, 2);
			rangeTelemetry = new BoolField(new ConfigPanel(configurator.rootPanel, "Debug logging", "debugLogging")
			{
				headerText = "These settings only write diagnostic information to the BepInEx log."
			}, "Log direct-hit ranges", "rangeTelemetry", false);
		}
	}
	[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;
			}
		}
	}
	[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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			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;
			}
			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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			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;
			}
			component.HandleCollision(other, velocity, Vector3.zero, ((Component)__instance).transform.position);
			return false;
		}
	}
	[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;
		}

		private static bool Prefix(Explosion __instance, Collider other, out State __state)
		{
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Invalid comparison between Unknown and I4
			__state = default(State);
			GrenadeLauncherExplosionMarker componentInParent = ((Component)__instance).GetComponentInParent<GrenadeLauncherExplosionMarker>();
			GrenadeLauncherProjectile grenadeLauncherProjectile = (((Object)(object)other != (Object)null) ? ((Component)other).GetComponentInParent<GrenadeLauncherProjectile>() : null);
			if ((Object)(object)grenadeLauncherProjectile != (Object)null && grenadeLauncherProjectile.IsStuck)
			{
				if ((Object)(object)componentInParent != (Object)null && componentInParent.Mode == GrenadeExplosionMode.Surface && !PluginSettings.TimedFuseDetonatesStuck)
				{
					return false;
				}
				if (!__instance.enemy && (Object)(object)__instance.sourceWeapon != (Object)null)
				{
					grenadeLauncherProjectile.DetonateStuck();
				}
				return false;
			}
			if ((Object)(object)componentInParent == (Object)null)
			{
				return true;
			}
			EnemyIdentifier val = GrenadeLauncherProjectile.TryGetLivingEnemy(other);
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			__state.Marker = componentInParent;
			__state.Enemy = val;
			if (PluginSettings.EnemyCarrierTakesDirectDamage && componentInParent.StuckHostEnemyId != 0 && ((Object)val).GetInstanceID() == componentInParent.StuckHostEnemyId)
			{
				__state.ChangedDamage = true;
				__state.Damage = __instance.damage;
				__instance.damage = Mathf.RoundToInt(Mathf.Max(0f, componentInParent.StuckCarrierDamage) * 10f);
			}
			if (componentInParent.Parried && (int)val.enemyType == 4)
			{
				componentInParent.DamageBlockedEnemy(val, other);
				return false;
			}
			__state.ChangedMultiplier = true;
			__state.EnemyDamageMultiplier = __instance.enemyDamageMultiplier;
			__instance.enemyDamageMultiplier *= PluginSettings.GetEnemyDamageMultiplier(val.enemyType);
			return true;
		}

		private static Exception Finalizer(Explosion __instance, State __state, Exception __exception)
		{
			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);
				__state.Marker.QueueDirectHitTelemetry(__state.Enemy);
			}
			return __exception;
		}
	}
	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 readonly HashSet<int> manuallyDamagedEnemies = new HashSet<int>();

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

		private bool walkingBombAwarded;

		private bool telemetryQueued;

		private EnemyIdentifier telemetryEnemy;

		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 void TryAwardLongRangeStyle(EnemyIdentifier enemy)
		{
			if (!((Object)(object)enemy == (Object)null) && LongRangeStyle != GrenadeLongRangeStyle.None && ((Object)enemy).GetInstanceID() == DirectEnemyId && styleAwardedEnemies.Add(DirectEnemyId))
			{
				GrenadeStyleAwards.Award(LongRangeStyle, enemy, SourceWeapon);
			}
		}

		internal void TryAwardWalkingBomb(EnemyIdentifier enemy)
		{
			if (!walkingBombAwarded && !((Object)(object)enemy == (Object)null) && enemy.dead && StuckHostEnemyId != 0 && ((Object)enemy).GetInstanceID() != StuckHostEnemyId)
			{
				walkingBombAwarded = true;
				GrenadeStyleAwards.AwardWalkingBomb(StuckChainGroupId, enemy, SourceWeapon);
			}
		}

		internal void QueueDirectHitTelemetry(EnemyIdentifier enemy)
		{
			if (PluginSettings.RangeTelemetryEnabled && !telemetryQueued && !((Object)(object)enemy == (Object)null) && DirectEnemyId != 0 && ((Object)enemy).GetInstanceID() == DirectEnemyId)
			{
				telemetryQueued = true;
				telemetryEnemy = enemy;
				((MonoBehaviour)this).StartCoroutine(LogDirectHitTelemetryAtEndOfFrame());
			}
		}

		private IEnumerator LogDirectHitTelemetryAtEndOfFrame()
		{
			yield return (object)new WaitForEndOfFrame();
			string arg = (((Object)(object)telemetryEnemy != (Object)null) ? ((object)Unsafe.As<EnemyType, EnemyType>(ref telemetryEnemy.enemyType)/*cast due to .constrained prefix*/).ToString() : "Destroyed");
			bool flag = (Object)(object)telemetryEnemy == (Object)null || telemetryEnemy.dead;
			float num = ((TheoreticalSameHeightRange > 0.001f) ? (DirectPlanarDistance / TheoreticalSameHeightRange) : 0f);
			string text = ((DirectProfile == GrenadeProjectileProfile.GreenContact) ? "GREEN" : "PRIMARY");
			ManualLogSource logSource = Plugin.LogSource;
			if (logSource != null)
			{
				logSource.LogInfo((object)("[RangeTelemetry] " + text + " direct hit | " + $"planar={DirectPlanarDistance:0.###}u | straight={DirectStraightDistance:0.###}u | " + $"launchElevation={LaunchElevationDegrees:0.###}deg | " + $"calculatedSameHeightMax={TheoreticalSameHeightRange:0.###}u | ratio={num:0.###} | " + $"styleThreshold={ConfiguredStyleThreshold:0.###}u | " + $"enemy={arg} | killed={flag}"));
			}
		}

		internal void DamageBlockedEnemy(EnemyIdentifier enemy, Collider hitCollider)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)enemy == (Object)null) && !enemy.dead && manuallyDamagedEnemies.Add(((Object)enemy).GetInstanceID()))
			{
				enemy.hitter = "grenadelauncherparry";
				float num = Damage * PluginSettings.GetEnemyDamageMultiplier(enemy.enemyType);
				Vector3 val;
				if (!((Object)(object)hitCollider != (Object)null))
				{
					val = ((Component)this).transform.position;
				}
				else
				{
					Bounds bounds = hitCollider.bounds;
					val = ((Bounds)(ref bounds)).ClosestPoint(((Component)this).transform.position);
				}
				Vector3 val2 = val;
				GameObject val3 = (((Object)(object)hitCollider != (Object)null) ? ((Component)hitCollider).gameObject : ((Component)enemy).gameObject);
				enemy.DeliverDamage(val3, Vector3.zero, val2, num, false, 0f, SourceWeapon, false, true);
			}
		}
	}
	[DefaultExecutionOrder(10000)]
	internal sealed class GrenadeLauncherProjectile : MonoBehaviour
	{
		private const float Tf2DemomanEyeHeightHu = 68f;

		private const float Tf2ForwardSpeedHu = 1200f;

		private const float Tf2UpwardSpeedHu = 200f;

		private const float Tf2GravityHu = 800f;

		private static int nextChainGroupId;

		internal Grenade Grenade;

		internal GrenadeProjectileProfile Profile;

		private Rigidbody body;

		private readonly List<CustomGravity> customGravityComponents = new List<CustomGravity>(1);

		private Collider[] ownColliders = Array.Empty<Collider>();

		private ParryReceiver parryReceiver;

		private bool launched;

		private bool finished;

		private bool bounced;

		private bool parried;

		private bool stuck;

		private int stuckHostEnemyId;

		private int chainGroupId;

		private bool wasHooked;

		private GelStainMarker stuckGelStain;

		private GelCoverage stuckGelCoverage;

		private float launchForwardSpeed;

		private float launchElevationDegrees;

		private float sameHeightMaximumRange;

		private Vector3 launchPosition;

		private Vector3 capturedGravity;

		private Collider lastBounceSurface;

		private Vector3 lastBounceNormal;

		private Vector3 lastBouncePoint;

		private bool hasLastBouncePoint;

		private float bornAt;

		private float fuseRemaining = -1f;

		private float chainDetonationAt = -1f;

		private Vector3 simulatedVelocity;

		private Vector3 lastVelocity;

		private Quaternion lastFixedRotation;

		private static bool loggedTrajectory;

		private static bool loggedExplosion;

		private static bool loggedPortalRotation;

		private static bool loggedRejectedExternalChange;

		internal bool CanBeWhiplashed
		{
			get
			{
				if (Profile == GrenadeProjectileProfile.Primary && bounced && !stuck)
				{
					return !finished;
				}
				return false;
			}
		}

		internal bool IsStuck
		{
			get
			{
				if (stuck)
				{
					return !finished;
				}
				return false;
			}
		}

		internal int ChainGroupId => chainGroupId;

		internal void Launch()
		{
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//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_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_034a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0354: Expected O, but got Unknown
			//IL_0316: Unknown result type (might be due to invalid IL or missing references)
			//IL_0320: Expected O, but got Unknown
			if (launched || (Object)(object)Grenade == (Object)null)
			{
				return;
			}
			launched = true;
			bornAt = Time.time;
			body = (((Object)(object)Grenade.rb != (Object)null) ? Grenade.rb : ((Component)this).GetComponent<Rigidbody>());
			if ((Object)(object)body == (Object)null)
			{
				Plugin.LogSource.LogWarning((object)"Grenade projectile had no Rigidbody; removing it.");
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			ownColliders = ((Component)this).GetComponentsInChildren<Collider>(true);
			float eyeHeight = TrajectoryCalibration.GetEyeHeight();
			float num = eyeHeight / 68f;
			float num2 = ((Profile == GrenadeProjectileProfile.GreenContact) ? (PluginSettings.SpeedMultiplier * PluginSettings.GreenSpeedMultiplier) : PluginSettings.SpeedMultiplier);
			float num3 = ((Profile == GrenadeProjectileProfile.GreenContact) ? (PluginSettings.UpwardVelocityMultiplier * PluginSettings.GreenUpwardVelocityMultiplier) : PluginSettings.UpwardVelocityMultiplier);
			float num4 = ((Profile == GrenadeProjectileProfile.GreenContact) ? (PluginSettings.GreenGravityMultiplier * PluginSettings.GravityMultiplier) : PluginSettings.GravityMultiplier);
			launchForwardSpeed = 1200f * num * Mathf.Max(0.05f, num2);
			float num5 = 200f * num * Mathf.Max(0f, num3);
			float num6 = 800f * num * Mathf.Max(0.05f, num4);
			launchPosition = ((Component)this).transform.position;
			Vector3 val = Physics.gravity;
			NewMovement instance = MonoSingleton<NewMovement>.Instance;
			if ((Object)(object)instance != (Object)null && (Object)(object)instance.rb != (Object)null)
			{
				val = PhysicsExtensions.GetGravityVector(instance.rb);
			}
			Vector3 val2 = Physics.gravity;
			float num7 = Mathf.Max(0.01f, ((Vector3)(ref val2)).magnitude);
			float num8 = ((Vector3)(ref val)).magnitude / num7;
			Vector3 val3 = ((((Vector3)(ref val)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val)).normalized : Vector3.down);
			capturedGravity = val3 * num6 * num8;
			LockNativeGravity();
			body.velocity = ((Component)this).transform.forward * launchForwardSpeed + ((Component)this).transform.up * num5;
			float magnitude = ((Vector3)(ref capturedGravity)).magnitude;
			float num9 = Vector3.Dot(body.velocity, -val3);
			val2 = Vector3.ProjectOnPlane(body.velocity, val3);
			float magnitude2 = ((Vector3)(ref val2)).magnitude;
			launchElevationDegrees = Mathf.Atan2(num9, Mathf.Max(0.0001f, magnitude2)) * 57.29578f;
			sameHeightMaximumRange = ((magnitude > 0.001f && num9 > 0f) ? (magnitude2 * (2f * num9 / magnitude)) : 0f);
			simulatedVelocity = body.velocity;
			lastVelocity = simulatedVelocity;
			lastFixedRotation = ((Component)this).transform.rotation;
			if (Profile == GrenadeProjectileProfile.Primary)
			{
				parryReceiver = ((Component)this).GetComponent<ParryReceiver>();
				if ((Object)(object)parryReceiver == (Object)null)
				{
					parryReceiver = ((Component)this).gameObject.AddComponent<ParryReceiver>();
				}
				if (parryReceiver.onParry == null)
				{
					parryReceiver.onParry = new UnityEvent();
				}
				parryReceiver.parryHeal = false;
				parryReceiver.disappearOnParry = false;
				parryReceiver.onParry.AddListener(new UnityAction(Parry));
				((Behaviour)parryReceiver).enabled = false;
			}
			else
			{
				parryReceiver = ((Component)this).GetComponent<ParryReceiver>();
				if ((Object)(object)parryReceiver != (Object)null)
				{
					((Behaviour)parryReceiver).enabled = false;
				}
			}
			if (!loggedTrajectory)
			{
				loggedTrajectory = true;
				Plugin.LogSource.LogInfo((object)($"TF2 trajectory converted from V1 eye height {eyeHeight:0.###}: " + $"forward {launchForwardSpeed:0.###} u/s, up {num5:0.###} u/s, " + $"captured gravity {capturedGravity} u/s²."));
			}
		}

		private void OnDestroy()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			if ((Object)(object)parryReceiver != (Object)null && parryReceiver.onParry != null)
			{
				parryReceiver.onParry.RemoveListener(new UnityAction(Parry));
			}
			GelSystem.UnregisterStuck(this);
		}

		private void FixedUpdate()
		{
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: 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_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_0355: Unknown result type (might be due to invalid IL or missing references)
			//IL_035a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0323: Unknown result type (might be due to invalid IL or missing references)
			//IL_0329: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0390: Unknown result type (might be due to invalid IL or missing references)
			//IL_0395: Unknown result type (might be due to invalid IL or missing references)
			//IL_0383: Unknown result type (might be due to invalid IL or missing references)
			//IL_039a: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_03af: Unknown result type (might be due to invalid IL or missing references)
			if (!launched || finished || (Object)(object)body == (Object)null)
			{
				return;
			}
			if (stuck)
			{
				if (chainDetonationAt >= 0f && Time.time >= chainDetonationAt)
				{
					DetonateStuck();
				}
				return;
			}
			float num = ((Profile == GrenadeProjectileProfile.GreenContact) ? PluginSettings.GreenLifetime : PluginSettings.Lifetime);
			if (Time.time - bornAt >= Mathf.Max(1f, num))
			{
				FinishSilently();
				return;
			}
			if ((Object)(object)Grenade != (Object)null && Grenade.hooked)
			{
				Grenade.CanCollideWithPlayer(false);
				if (!wasHooked && bounced && !parried && fuseRemaining >= 0f)
				{
					fuseRemaining += Mathf.Max(0f, PluginSettings.HookFuseGrace);
				}
				wasHooked = true;
				lastFixedRotation = ((Component)this).transform.rotation;
				return;
			}
			if (wasHooked)
			{
				wasHooked = false;
				if (!body.isKinematic)
				{
					simulatedVelocity = body.velocity;
					lastVelocity = simulatedVelocity;
				}
			}
			if ((Object)(object)Grenade != (Object)null && Grenade.frozen)
			{
				return;
			}
			if (bounced && !parried && fuseRemaining >= 0f)
			{
				fuseRemaining -= Time.fixedDeltaTime;
				if (fuseRemaining <= 0f)
				{
					Explode(GrenadeExplosionMode.Surface);
					return;
				}
			}
			if (body.isKinematic)
			{
				lastFixedRotation = ((Component)this).transform.rotation;
				return;
			}
			Vector3 velocity = body.velocity;
			Vector3 val = lastVelocity;
			Vector3 val2 = velocity - val;
			bool flag = ((Vector3)(ref val2)).sqrMagnitude > 4f && Time.time - bornAt > Time.fixedDeltaTime * 2f;
			bool flag2 = flag && IsMagnitudePreservingRotation(val, velocity);
			if (flag2)
			{
				Quaternion val3 = ((Component)this).transform.rotation * Quaternion.Inverse(lastFixedRotation);
				simulatedVelocity = velocity;
				lastVelocity = velocity;
				capturedGravity = val3 * capturedGravity;
			}
			if (flag2 && !loggedPortalRotation)
			{
				loggedPortalRotation = true;
				Plugin.LogSource.LogInfo((object)("Detected a seamless portal transform; rotating the captured launch trajectory and gravity. " + $"expected {val}, actual {velocity}, " + $"rigidbody gravity={body.useGravity}, world gravity={Physics.gravity}."));
			}
			else if (flag && !flag2 && !loggedRejectedExternalChange)
			{
				loggedRejectedExternalChange = true;
				Plugin.LogSource.LogWarning((object)("Rejected an external grenade velocity change to preserve the custom trajectory: " + $"expected {val}, actual {velocity}, " + $"rigidbody gravity={body.useGravity}, world gravity={Physics.gravity}."));
			}
			LockNativeGravity();
			if (!parried)
			{
				simulatedVelocity += capturedGravity * Time.fixedDeltaTime;
			}
			body.velocity = simulatedVelocity;
			lastVelocity = simulatedVelocity;
			if (((Vector3)(ref simulatedVelocity)).sqrMagnitude > 0.01f)
			{
				Vector3 val4 = ((((Vector3)(ref capturedGravity)).sqrMagnitude > 0.001f) ? (-((Vector3)(ref capturedGravity)).normalized) : Vector3.up);
				((Component)this).transform.rotation = Quaternion.LookRotation(((Vector3)(ref simulatedVelocity)).normalized, val4);
			}
			lastFixedRotation = ((Component)this).transform.rotation;
		}

		private static bool IsMagnitudePreservingRotation(Vector3 before, Vector3 after)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			float magnitude = ((Vector3)(ref before)).magnitude;
			float magnitude2 = ((Vector3)(ref after)).magnitude;
			if (magnitude < 0.5f || magnitude2 < 0.5f)
			{
				return false;
			}
			float num = Mathf.Max(0.35f, magnitude * 0.015f);
			if (Mathf.Abs(magnitude - magnitude2) <= num)
			{
				return Vector3.Angle(before, after) >= 2f;
			}
			return false;
		}

		private void LockNativeGravity()
		{
			if ((Object)(object)body == (Object)null)
			{
				return;
			}
			body.useGravity = false;
			PhysicsExtensions.SetGravityMode(body, false);
			((Component)body).GetComponents<CustomGravity>(customGravityComponents);
			foreach (CustomGravity customGravityComponent in customGravityComponents)
			{
				if ((Object)(object)customGravityComponent != (Object)null)
				{
					customGravityComponent.useGravity = false;
				}
			}
		}

		internal void HandleCollision(Collider other, Vector3 incomingVelocity, Vector3 collisionNormal, Vector3 collisionPoint)
		{
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Invalid comparison between Unknown and I4
			if (finished || (Object)(object)other == (Object)null || stuck || ((Component)other).CompareTag("Player") || ((Component)other).gameObject.layer == 14 || ((Component)other).gameObject.layer == 20)
			{
				return;
			}
			if ((Object)(object)((Component)other).GetComponentInParent<Grenade>() != (Object)null)
			{
				Collider[] array = ownColliders;
				foreach (Collider val in array)
				{
					if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)other)
					{
						Physics.IgnoreCollision(val, other, true);
					}
				}
				if ((Object)(object)body != (Object)null && !body.isKinematic)
				{
					body.velocity = simulatedVelocity;
				}
				return;
			}
			if (Profile == GrenadeProjectileProfile.Primary)
			{
				Glass componentInParent = ((Component)other).GetComponentInParent<Glass>();
				if ((Object)(object)componentInParent != (Object)null)
				{
					componentInParent.Shatter();
					Collider[] array = ownColliders;
					foreach (Collider val2 in array)
					{
						if ((Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)other)
						{
							Physics.IgnoreCollision(val2, other, true);
						}
					}
					if ((Object)(object)body != (Object)null && !body.isKinematic)
					{
						body.velocity = simulatedVelocity;
					}
					return;
				}
			}
			EnemyIdentifier val3 = TryGetLivingEnemy(other);
			if (!other.isTrigger || !((Object)(object)val3 == (Object)null))
			{
				if (GelSystem.TryGetStickTarget(other, val3, collisionPoint, out var stain, out var coverage))
				{
					StickToGel(other, collisionNormal, collisionPoint, val3, stain, coverage);
				}
				else if (Profile == GrenadeProjectileProfile.GreenContact)
				{
					Explode(((Object)(object)val3 != (Object)null) ? GrenadeExplosionMode.GreenDirect : GrenadeExplosionMode.GreenSurface, val3);
				}
				else if (parried)
				{
					Explode(GrenadeExplosionMode.Parried);
				}
				else if (!bounced && (Object)(object)val3 != (Object)null && (int)val3.enemyType != 4)
				{
					Explode(GrenadeExplosionMode.Direct, val3);
				}
				else
				{
					Bounce(other, incomingVelocity, collisionNormal, collisionPoint);
				}
			}
		}

		internal static EnemyIdentifier TryGetLivingEnemy(Collider other)
		{
			if ((Object)(object)other == (Object)null)
			{
				return null;
			}
			EnemyIdentifierIdentifier val = null;
			if ((Object)(object)other.attachedRigidbody != (Object)null)
			{
				val = ((Component)other.attachedRigidbody).GetComponent<EnemyIdentifierIdentifier>();
			}
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)other).GetComponentInParent<EnemyIdentifierIdentifier>();
			}
			if ((Object)(object)val != (Object)null && (Object)(object)val.eid != (Object)null && !val.eid.dead)
			{
				return val.eid;
			}
			EnemyIdentifier componentInParent = ((Component)other).GetComponentInParent<EnemyIdentifier>();
			if (!((Object)(object)componentInParent != (Object)null) || componentInParent.dead)
			{
				return null;
			}
			return componentInParent;
		}

		private void Bounce(Collider surface, Vector3 incomingVelocity, Vector3 collisionNormal, Vector3 collisionPoint)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)body == (Object)null)
			{
				return;
			}
			if (!bounced)
			{
				bounced = true;
				fuseRemaining = Mathf.Max(0.1f, PluginSettings.SurfaceFuse);
				if ((Object)(object)parryReceiver != (Object)null)
				{
					((Behaviour)parryReceiver).enabled = true;
				}
			}
			Vector3 val = ((((Vector3)(ref lastVelocity)).sqrMagnitude > 0.01f) ? lastVelocity : incomingVelocity);
			Vector3 val2 = collisionNormal;
			if (((Vector3)(ref val2)).sqrMagnitude < 0.01f)
			{
				Bounds bounds = surface.bounds;
				Vector3 val3 = ((Bounds)(ref bounds)).ClosestPoint(((Component)this).transform.position);
				val2 = ((Component)this).transform.position - val3;
			}
			if (((Vector3)(ref val2)).sqrMagnitude < 0.01f)
			{
				val2 = ((((Vector3)(ref val)).sqrMagnitude > 0.01f) ? (-((Vector3)(ref val)).normalized) : (-((Vector3)(ref capturedGravity)).normalized));
			}
			((Vector3)(ref val2)).Normalize();
			if (((Vector3)(ref val)).sqrMagnitude > 0.01f && Vector3.Dot(val2, val) > 0f)
			{
				val2 = -val2;
			}
			lastBounceSurface = surface;
			lastBounceNormal = val2;
			lastBouncePoint = collisionPoint;
			hasLastBouncePoint = true;
			float num = Mathf.Clamp01(PluginSettings.BounceRetention);
			body.constraints = (RigidbodyConstraints)0;
			simulatedVelocity = Vector3.Reflect(val, val2) * num;
			if (!body.isKinematic)
			{
				body.velocity = simulatedVelocity;
				Rigidbody obj = body;
				obj.angularVelocity *= num;
			}
			lastVelocity = simulatedVelocity;
		}

		private void Parry()
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: 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_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			if (!finished && bounced && !((Object)(object)body == (Object)null))
			{
				parried = true;
				fuseRemaining = -1f;
				if ((Object)(object)parryReceiver != (Object)null)
				{
					((Behaviour)parryReceiver).enabled = false;
				}
				Grenade.CanCollideWithPlayer(false);
				CameraController instance = MonoSingleton<CameraController>.Instance;
				Vector3 val = (((Object)(object)instance != (Object)null) ? ((Component)instance).transform.forward : ((Component)this).transform.forward);
				body.constraints = (RigidbodyConstraints)0;
				simulatedVelocity = ((Vector3)(ref val)).normalized * launchForwardSpeed * Mathf.Max(0.1f, PluginSettings.ParrySpeedMultiplier);
				if (body.isKinematic)
				{
					body.isKinematic = false;
				}
				body.velocity = simulatedVelocity;
				body.angularVelocity = Vector3.zero;
				lastVelocity = simulatedVelocity;
				((Component)this).transform.rotation = Quaternion.LookRotation(((Vector3)(ref val)).normalized, ((Component)this).transform.up);
				if (IsParriedIntoLastSurface(((Vector3)(ref val)).normalized))
				{
					Explode(GrenadeExplosionMode.Parried);
				}
			}
		}

		private bool IsParriedIntoLastSurface(Vector3 direction)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: 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)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: 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_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)lastBounceSurface == (Object)null)
			{
				return false;
			}
			float fullProjectileClearance = GetFullProjectileClearance();
			RaycastHit val = default(RaycastHit);
			bool num = lastBounceSurface.Raycast(new Ray(((Component)this).transform.position, direction), ref val, fullProjectileClearance);
			Vector3 val2 = ((Component)this).transform.position - direction * fullProjectileClearance;
			RaycastHit val3 = default(RaycastHit);
			bool num2 = lastBounceSurface.Raycast(new Ray(val2, direction), ref val3, fullProjectileClearance * 2f);
			float num3 = (num2 ? Vector3.Dot(((RaycastHit)(ref val3)).point - ((Component)this).transform.position, direction) : float.PositiveInfinity);
			bool flag = num2 && num3 >= -0.05f;
			RaycastHit val4 = default(RaycastHit);
			bool flag2 = Physics.Raycast(((Component)this).transform.position, direction, ref val4, fullProjectileClearance, -1, (QueryTriggerInteraction)1) && (Object)(object)((RaycastHit)(ref val4)).collider != (Object)null && !((Component)((RaycastHit)(ref val4)).collider).transform.IsChildOf(((Component)this).transform) && !((Component)((RaycastHit)(ref val4)).collider).CompareTag("Player");
			Bounds bounds = lastBounceSurface.bounds;
			Vector3 val5 = ((Bounds)(ref bounds)).ClosestPoint(((Component)this).transform.position);
			float num4 = Vector3.Distance(((Component)this).transform.position, val5);
			float num5 = (hasLastBouncePoint ? Vector3.Distance(((Component)this).transform.position, lastBouncePoint) : float.PositiveInfinity);
			float num6 = ((((Vector3)(ref lastBounceNormal)).sqrMagnitude >= 0.01f) ? Vector3.Dot(direction, lastBounceNormal) : float.NaN);
			bool num7 = ((Vector3)(ref lastBounceNormal)).sqrMagnitude >= 0.01f && num6 < -0.05f;
			Vector3 val6 = (hasLastBouncePoint ? (lastBouncePoint - ((Component)this).transform.position) : Vector3.zero);
			float num8 = (hasLastBouncePoint ? Mathf.Abs(Vector3.Dot(val6, lastBounceNormal)) : float.PositiveInfinity);
			float num9;
			if (!hasLastBouncePoint)
			{
				num9 = float.PositiveInfinity;
			}
			else
			{
				Vector3 val7 = Vector3.ProjectOnPlane(val6, lastBounceNormal);
				num9 = ((Vector3)(ref val7)).magnitude;
			}
			float num10 = num9;
			bool flag3 = hasLastBouncePoint && num8 <= fullProjectileClearance + 0.25f && num10 <= fullProjectileClearance;
			bool flag4 = num7 && (num4 <= fullProjectileClearance || num5 <= fullProjectileClearance || flag3);
			return num || flag || flag2 || flag4;
		}

		private float GetFullProjectileClearance()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			float num = 0.75f;
			Collider[] array = ownColliders;
			foreach (Collider val in array)
			{
				if (!((Object)(object)val == (Object)null) && val.enabled && !val.isTrigger)
				{
					Bounds bounds = val.bounds;
					float num2 = Vector3.Distance(((Component)this).transform.position, ((Bounds)(ref bounds)).center);
					Vector3 extents = ((Bounds)(ref bounds)).extents;
					float num3 = num2 + ((Vector3)(ref extents)).magnitude;
					num = Mathf.Max(num, num3 + 0.2f);
				}
			}
			return num;
		}

		private void StickToGel(Collider surface, Vector3 collisionNormal, Vector3 collisionPoint, EnemyIdentifier hostEnemy, GelStainMarker gelStain, GelCoverage gelCoverage)
		{
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to