Decompiled source of ThrowEverything v0.4.1

Spantle.ThrowEverything.dll

Decompiled 10 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LethalCompanyInputUtils.Api;
using Microsoft.CodeAnalysis;
using ThrowEverything.Models;
using ThrowEverything.Patches;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;

[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("Spantle")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Adds a new ability to throw (almost) any item in Lethal Company. Throw items to deal damage, distract enemies, trigger landmines, and more!")]
[assembly: AssemblyFileVersion("0.4.1.0")]
[assembly: AssemblyInformationalVersion("0.4.1")]
[assembly: AssemblyProduct("ThrowEverything")]
[assembly: AssemblyTitle("Spantle.ThrowEverything")]
[assembly: AssemblyVersion("0.4.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 ThrowEverything
{
	internal class ControlTips
	{
		internal static void Set(GrabbableObject item)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				ChargingThrow chargingThrow = State.GetChargingThrow();
				Item itemProperties = item.itemProperties;
				int num = 1;
				if (itemProperties.toolTips != null)
				{
					num = itemProperties.toolTips.Length + 1;
					if (num > 3)
					{
						return;
					}
				}
				string[] array = new string[num];
				string itemName = itemProperties.itemName;
				if (chargingThrow.isCharging)
				{
					int chargedPercentage = chargingThrow.GetChargedPercentage();
					array[0] = $"Throw {itemName} : [{chargedPercentage}%]";
				}
				else
				{
					InputBinding val = InputSettings.Instance.ThrowItem.bindings[0];
					string text = ((InputBinding)(ref val)).path.Split('/').Last().ToUpper();
					array[0] = "Throw " + itemName + " : [" + text + "]";
				}
				for (int i = 1; i < array.Length; i++)
				{
					array[i] = itemProperties.toolTips[i - 1];
				}
				HUDManager.Instance.ChangeControlTipMultiple(array, true, itemProperties);
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)"failed to inject control tips");
				Plugin.Logger.LogWarning((object)ex);
			}
		}
	}
	internal class InputSettings : LcInputActions
	{
		public static readonly InputSettings Instance = new InputSettings();

		[InputAction("<Keyboard>/r", Name = "ThrowEverything: Throw Item")]
		public InputAction ThrowItem { get; set; }
	}
	[BepInPlugin("Spantle.ThrowEverything", "ThrowEverything", "0.4.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		private readonly Harmony harmony = new Harmony("Spantle.ThrowEverything");

		internal static ManualLogSource Logger;

		private void Awake()
		{
			Logger = ((BaseUnityPlugin)this).Logger;
			harmony.PatchAll(typeof(GrabbableObject_Patch));
			harmony.PatchAll(typeof(HUDManager_Patch));
			harmony.PatchAll(typeof(PlayerControllerB_Patch));
			if (((LcInputActions)InputSettings.Instance).Enabled)
			{
				Logger.LogInfo((object)"InputUtils is working");
			}
			Logger.LogInfo((object)"Spantle.ThrowEverything is loaded!");
		}
	}
	internal class State
	{
		private static Throwable heldThrowable = null;

		private static readonly ChargingThrow chargingThrow = new ChargingThrow();

		private static readonly ThrownItems thrownItems = new ThrownItems();

		internal static void SetHeldThrowable(GrabbableObject item)
		{
			heldThrowable = new Throwable(item, item.playerHeldBy);
			heldThrowable.HookEvents();
		}

		internal static void ClearHeldThrowable()
		{
			chargingThrow.Stop();
			if (heldThrowable != null)
			{
				heldThrowable.UnhookEvents();
				heldThrowable = null;
			}
		}

		internal static Throwable GetHeldThrowable()
		{
			return heldThrowable;
		}

		internal static ChargingThrow GetChargingThrow()
		{
			return chargingThrow;
		}

		internal static ThrownItems GetThrownItems()
		{
			return thrownItems;
		}
	}
	internal class Utils
	{
		internal static string Name(GrabbableObject __instance)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return "NULL";
			}
			if ((Object)(object)__instance.itemProperties == (Object)null)
			{
				return ((Object)__instance).name + " (props was NULL)";
			}
			return ((Object)__instance.itemProperties).name;
		}

		internal static float ItemWeight(GrabbableObject __instance)
		{
			float weight = __instance.itemProperties.weight;
			float num = ((!__instance.itemProperties.twoHanded) ? 1 : 2);
			return Math.Clamp((weight - 1f) * num, 0f, 1f);
		}

		internal static float ItemPower(GrabbableObject __instance, float powerDecimal, bool inverse = false)
		{
			float num = ItemWeight(__instance);
			float value = ((!inverse) ? (num * num) : ((1f - num) * (1f - num)));
			value = Math.Clamp(value, 0f, 1f);
			return value * powerDecimal;
		}

		internal static float ItemScale(GrabbableObject __instance)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 localScale = ((Component)__instance).transform.localScale;
			return Math.Clamp(((Vector3)(ref localScale)).magnitude, 0.2f, 3f);
		}

		internal static void DamagePlayer(PlayerControllerB player, int damage, Vector3 hitDirection, PlayerControllerB damager)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (player.AllowPlayerDeath() && !Object.op_Implicit((Object)(object)player.inAnimationWithEnemy))
			{
				player.DamagePlayerFromOtherClientServerRpc(damage, hitDirection, (int)damager.playerClientId);
			}
		}

		internal static Vector3 FindLandingRay(Vector3 location, bool logging = false)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			Ray val = default(Ray);
			((Ray)(ref val))..ctor(location, Vector3.down);
			RaycastHit val2 = default(RaycastHit);
			if (Physics.Raycast(val, ref val2, 100f, StartOfRound.Instance.collidersAndRoomMaskAndDefault))
			{
				if (logging)
				{
					Plugin.Logger.LogInfo((object)"we hit the floor");
				}
				return ((RaycastHit)(ref val2)).point + Vector3.up * 0.05f;
			}
			if (logging)
			{
				Plugin.Logger.LogInfo((object)"we did not hit the floor");
			}
			return ((Ray)(ref val)).GetPoint(100f);
		}

		internal static Vector3 GetItemThrowDestination(GrabbableObject item, PlayerControllerB thrower, float chargeDecimal)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: 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_00ed: Unknown result type (might be due to invalid IL or missing references)
			Ray val = default(Ray);
			((Ray)(ref val))..ctor(((Component)thrower.gameplayCamera).transform.position, ((Component)thrower.gameplayCamera).transform.forward);
			float num = ItemPower(item, chargeDecimal, inverse: true) * 20f;
			RaycastHit val2 = default(RaycastHit);
			float num2;
			if (Physics.Raycast(val, ref val2, num, StartOfRound.Instance.collidersAndRoomMaskAndDefault))
			{
				Plugin.Logger.LogInfo((object)"we hit a surface");
				num2 = ((RaycastHit)(ref val2)).distance;
			}
			else
			{
				Plugin.Logger.LogInfo((object)"we did not hit a surface");
				num2 = num;
			}
			num2 = Math.Max(0f, num2 - ItemScale(item) / 2f);
			Plugin.Logger.LogInfo((object)$"throwing {Name(item)} ({item.itemProperties.weight}): {num2} units ({num}, {ItemScale(item)})");
			return FindLandingRay(((Ray)(ref val)).GetPoint(num2));
		}

		internal static Vector3 GetItemThrowDestination(ThrownItem thrownItem)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return GetItemThrowDestination(thrownItem.GetItem(), thrownItem.GetThrower(), thrownItem.GetChargeDecimal());
		}

		internal static bool CanUseItem(PlayerControllerB player)
		{
			if ((!((NetworkBehaviour)player).IsOwner || !player.isPlayerControlled || (((NetworkBehaviour)player).IsServer && !player.isHostPlayerObject)) && !player.isTestingPlayer)
			{
				return false;
			}
			if (!player.isHoldingObject || (Object)(object)player.currentlyHeldObjectServer == (Object)null)
			{
				return false;
			}
			if (player.quickMenuManager.isMenuOpen)
			{
				return false;
			}
			if (player.isPlayerDead)
			{
				return false;
			}
			if (!player.currentlyHeldObjectServer.itemProperties.usableInSpecialAnimations && (player.isGrabbingObjectAnimation || player.inTerminalMenu || player.isTypingChat || (player.inSpecialInteractAnimation && !player.inShockingMinigame)))
			{
				return false;
			}
			return true;
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "Spantle.ThrowEverything";

		public const string PLUGIN_NAME = "ThrowEverything";

		public const string PLUGIN_VERSION = "0.4.1";
	}
}
namespace ThrowEverything.Patches
{
	[HarmonyPatch(typeof(GrabbableObject))]
	public class GrabbableObject_Patch
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(GrabbableObject), "EquipItem")]
		private static void EquipItem(GrabbableObject __instance)
		{
			if (((NetworkBehaviour)__instance).IsOwner)
			{
				Plugin.Logger.LogInfo((object)("equipped " + Utils.Name(__instance)));
				State.ClearHeldThrowable();
				State.SetHeldThrowable(__instance);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GrabbableObject), "PocketItem")]
		private static void PocketItem(GrabbableObject __instance)
		{
			if (((NetworkBehaviour)__instance).IsOwner)
			{
				Plugin.Logger.LogInfo((object)("pocketed " + Utils.Name(__instance)));
				State.ClearHeldThrowable();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GrabbableObject), "DiscardItem")]
		private static void DiscardItem(GrabbableObject __instance)
		{
			if (((NetworkBehaviour)__instance).IsOwner)
			{
				Plugin.Logger.LogInfo((object)("discarded " + Utils.Name(__instance)));
				State.ClearHeldThrowable();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GrabbableObject), "SetControlTipsForItem")]
		private static void SetControlTipsForItem(GrabbableObject __instance)
		{
			ControlTips.Set(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GrabbableObject), "Update")]
		private static void Update(GrabbableObject __instance)
		{
			ThrownItems thrownItems = State.GetThrownItems();
			if (thrownItems.thrownItemsDict.TryGetValue(((Object)__instance).GetInstanceID(), out var value))
			{
				thrownItems.Update(value);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(GrabbableObject), "FallWithCurve")]
		private static bool FallWithCurve(GrabbableObject __instance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_005b: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: 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_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = __instance.startFallingPosition - __instance.targetFloorPosition;
			float magnitude = ((Vector3)(ref val)).magnitude;
			((Component)__instance).transform.rotation = Quaternion.Lerp(((Component)__instance).transform.rotation, Quaternion.Euler(__instance.itemProperties.restingRotation.x, ((Component)__instance).transform.eulerAngles.y, __instance.itemProperties.restingRotation.z), 14f * Time.deltaTime / magnitude);
			((Component)__instance).transform.localPosition = Vector3.Lerp(__instance.startFallingPosition, __instance.targetFloorPosition, FallCurve.fallCurve.Evaluate(__instance.fallTime));
			if (magnitude > 5f)
			{
				((Component)__instance).transform.localPosition = Vector3.Lerp(new Vector3(((Component)__instance).transform.localPosition.x, __instance.startFallingPosition.y, ((Component)__instance).transform.localPosition.z), new Vector3(((Component)__instance).transform.localPosition.x, __instance.targetFloorPosition.y, ((Component)__instance).transform.localPosition.z), FallCurve.verticalFallCurveNoBounce.Evaluate(__instance.fallTime));
			}
			else
			{
				((Component)__instance).transform.localPosition = Vector3.Lerp(new Vector3(((Component)__instance).transform.localPosition.x, __instance.startFallingPosition.y, ((Component)__instance).transform.localPosition.z), new Vector3(((Component)__instance).transform.localPosition.x, __instance.targetFloorPosition.y, ((Component)__instance).transform.localPosition.z), FallCurve.verticalFallCurve.Evaluate(__instance.fallTime));
			}
			__instance.fallTime += Mathf.Abs(Time.deltaTime * 12f / magnitude);
			return false;
		}
	}
	[HarmonyPatch(typeof(HUDManager))]
	public class HUDManager_Patch
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(HUDManager), "Update")]
		private static void Update(HUDManager __instance)
		{
			Throwable heldThrowable = State.GetHeldThrowable();
			if (heldThrowable != null)
			{
				ControlTips.Set(heldThrowable.GetItem());
			}
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB))]
	public class PlayerControllerB_Patch
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerControllerB), "Update")]
		private static void Update(PlayerControllerB __instance)
		{
			if ((Object)(object)StartOfRound.Instance.localPlayerController != (Object)(object)__instance)
			{
				return;
			}
			ChargingThrow chargingThrow = State.GetChargingThrow();
			if (chargingThrow.isCharging)
			{
				chargingThrow.DrawLandingCircle();
				if (!chargingThrow.hasFullyCharged)
				{
					__instance.sprintMeter = Mathf.Clamp(__instance.sprintMeter - 0.0025f, 0f, 1f);
				}
				else
				{
					__instance.sprintMeter = Mathf.Clamp(__instance.sprintMeter - 0.00125f, 0f, 1f);
				}
			}
			if (__instance.sprintMeter < 0.3f || __instance.isExhausted)
			{
				__instance.isExhausted = true;
				chargingThrow.Exhausted();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerControllerB), "ScrollMouse_performed")]
		private static void ScrollMouse_performed(PlayerControllerB __instance)
		{
			if (State.GetChargingThrow().isCharging)
			{
				__instance.isGrabbingObjectAnimation = false;
			}
			if (Utils.CanUseItem(__instance))
			{
				Throwable heldThrowable = State.GetHeldThrowable();
				if (heldThrowable != null)
				{
					GrabbableObject item = heldThrowable.GetItem();
					State.ClearHeldThrowable();
					State.SetHeldThrowable(item);
				}
			}
		}
	}
}
namespace ThrowEverything.Models
{
	internal class ChargingThrow
	{
		private const int MIN_CHARGING_TIME = 500;

		private const int MAX_CHARGING_TIME = 2000;

		internal bool isCharging;

		internal DateTime startChargingTime;

		internal bool hasRunOutOfStamina;

		internal DateTime runOutOfStaminaTime;

		internal bool hasFullyCharged;

		private GameObject preview;

		internal void StartCharging()
		{
			isCharging = true;
			startChargingTime = DateTime.Now;
			hasRunOutOfStamina = false;
			hasFullyCharged = false;
		}

		internal void Stop()
		{
			isCharging = false;
			hasRunOutOfStamina = false;
			hasFullyCharged = false;
			Object.Destroy((Object)(object)preview);
		}

		internal void Exhausted()
		{
			if (!hasRunOutOfStamina)
			{
				hasRunOutOfStamina = true;
				runOutOfStaminaTime = DateTime.Now;
			}
		}

		private float GetTime()
		{
			if (hasRunOutOfStamina)
			{
				return (float)(runOutOfStaminaTime - startChargingTime).TotalMilliseconds;
			}
			return (float)(DateTime.Now - startChargingTime).TotalMilliseconds;
		}

		internal float GetChargeDecimal()
		{
			float num = Utils.ItemWeight(State.GetHeldThrowable().GetItem());
			float num2 = Math.Clamp(GetTime() / (float)Math.Clamp((int)Math.Round(num * 2000f), 500, 2000), 0f, 1f);
			if (isCharging && num2 == 1f)
			{
				hasFullyCharged = true;
			}
			return num2;
		}

		internal int GetChargedPercentage()
		{
			return (int)Math.Floor(GetChargeDecimal() * 100f);
		}

		internal void DrawLandingCircle()
		{
			//IL_0068: 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)
			if ((Object)(object)preview == (Object)null)
			{
				preview = GameObject.CreatePrimitive((PrimitiveType)0);
				preview.layer = 6;
				preview.GetComponent<Renderer>().material = ShipBuildModeManager.Instance.ghostObjectGreen;
			}
			Throwable heldThrowable = State.GetHeldThrowable();
			ChargingThrow chargingThrow = State.GetChargingThrow();
			GrabbableObject item = heldThrowable.GetItem();
			float num = Utils.ItemScale(item);
			preview.transform.localScale = new Vector3(num, num, num);
			preview.transform.position = Utils.GetItemThrowDestination(item, heldThrowable.GetThrower(), chargingThrow.GetChargeDecimal());
		}
	}
	internal class FallCurve
	{
		internal static readonly Keyframe[] fallCurveKeyframes = (Keyframe[])(object)new Keyframe[2]
		{
			new Keyframe(0f, 0f, 2f, 2f),
			new Keyframe(1f, 1f, 0f, 0f)
		};

		internal static readonly Keyframe[] verticalFallCurveKeyframes = (Keyframe[])(object)new Keyframe[5]
		{
			new Keyframe(0f, 0f, 0.116908506f, 0.116908506f, 0f, 0.27230743f),
			new Keyframe(0.49081117f, 1f, 4.1146584f, -1.81379f, 0.07234045f, 0.28319725f),
			new Keyframe(0.7587703f, 1f, 1.4123471f, -1.3678839f, 0.31997186f, 0.56917864f),
			new Keyframe(0.9393898f, 1f, 0.82654804f, -0.029021755f, 0.53747445f, 1f),
			new Keyframe(1f, 1f)
		};

		internal static readonly Keyframe[] verticalFallCurveNoBounceKeyFrames = (Keyframe[])(object)new Keyframe[4]
		{
			new Keyframe(0f, 0f, 0.116908506f, 0.116908506f, 0f, 0.27230743f),
			new Keyframe(0.69081116f, 1f, 0.1146584f, 0.06098772f, 0.07234045f, 0.20768756f),
			new Keyframe(0.9393898f, 1f, 0.06394797f, -0.029021755f, 0.1980713f, 1f),
			new Keyframe(1f, 1f)
		};

		internal static readonly AnimationCurve fallCurve = new AnimationCurve(fallCurveKeyframes);

		internal static readonly AnimationCurve verticalFallCurve = new AnimationCurve(verticalFallCurveKeyframes);

		internal static readonly AnimationCurve verticalFallCurveNoBounce = new AnimationCurve(verticalFallCurveNoBounceKeyFrames);
	}
	internal class Throwable
	{
		private readonly GrabbableObject item;

		private readonly PlayerControllerB thrower;

		internal Throwable(GrabbableObject item, PlayerControllerB thrower)
		{
			this.item = item;
			this.thrower = thrower;
		}

		internal GrabbableObject GetItem()
		{
			return item;
		}

		internal PlayerControllerB GetThrower()
		{
			return thrower;
		}

		internal void StartThrowing(CallbackContext ctx)
		{
			if (!Utils.CanUseItem(thrower))
			{
				Plugin.Logger.LogInfo((object)"cannot use item");
				return;
			}
			thrower.isGrabbingObjectAnimation = true;
			State.GetChargingThrow().StartCharging();
		}

		internal void Throw(CallbackContext ctx)
		{
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			thrower.isGrabbingObjectAnimation = false;
			if ((Object)(object)item == (Object)null || (Object)(object)item.playerHeldBy != (Object)(object)thrower)
			{
				Plugin.Logger.LogWarning((object)$"tried to throw an invalid item {(Object)(object)item == (Object)null}");
				State.ClearHeldThrowable();
				return;
			}
			ChargingThrow chargingThrow = State.GetChargingThrow();
			if (!chargingThrow.isCharging)
			{
				Plugin.Logger.LogInfo((object)"tried to throw without charging");
				return;
			}
			float chargeDecimal = chargingThrow.GetChargeDecimal();
			float markiplier = Utils.ItemPower(item, chargeDecimal);
			ThrownItem thrownItem = new ThrownItem(item, item.playerHeldBy, chargeDecimal, markiplier);
			State.GetThrownItems().thrownItemsDict.Add(((Object)item).GetInstanceID(), thrownItem);
			item.playerHeldBy.DiscardHeldObject(true, (NetworkObject)null, Utils.GetItemThrowDestination(thrownItem), true);
		}

		internal void HookEvents()
		{
			InputSettings.Instance.ThrowItem.started += StartThrowing;
			InputSettings.Instance.ThrowItem.canceled += Throw;
		}

		internal void UnhookEvents()
		{
			InputSettings.Instance.ThrowItem.started -= StartThrowing;
			InputSettings.Instance.ThrowItem.canceled -= Throw;
			thrower.isGrabbingObjectAnimation = false;
		}
	}
	internal class ThrownItem
	{
		private readonly GrabbableObject item;

		private readonly PlayerControllerB thrower;

		private readonly float chargeDecimal;

		private readonly float markiplier;

		private readonly DateTime thrownAt;

		private readonly List<IHittable> hits = new List<IHittable>();

		internal ThrownItem(GrabbableObject item, PlayerControllerB thrower, float chargeDecimal, float markiplier)
		{
			this.item = item;
			this.thrower = thrower;
			this.chargeDecimal = chargeDecimal;
			this.markiplier = markiplier;
			thrownAt = DateTime.Now;
		}

		internal GrabbableObject GetItem()
		{
			return item;
		}

		internal PlayerControllerB GetThrower()
		{
			return thrower;
		}

		internal float GetMarkiplier()
		{
			return markiplier;
		}

		internal float GetChargeDecimal()
		{
			return chargeDecimal;
		}

		internal bool CheckIfHitOrAdd(IHittable hittable)
		{
			if (hits.Contains(hittable))
			{
				return true;
			}
			hits.Add(hittable);
			return false;
		}

		internal bool IsPanicking()
		{
			return (DateTime.Now - thrownAt).TotalMilliseconds >= 5000.0;
		}

		internal void LandAndRemove()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			float num = 1f - (1f - markiplier) * (1f - markiplier);
			Plugin.Logger.LogInfo((object)$"playing sound for {((Object)item).name} at markiplier {num}");
			RoundManager.Instance.PlayAudibleNoise(((Component)item).transform.position, Math.Clamp(num * 50f, 8f, 50f), Math.Clamp(num, 0.5f, 1f), 0, item.isInElevator && StartOfRound.Instance.hangarDoorsClosed, 941);
			State.GetThrownItems().thrownItemsDict.Remove(((Object)item).GetInstanceID());
		}
	}
	internal class ThrownItems
	{
		internal Dictionary<int, ThrownItem> thrownItemsDict = new Dictionary<int, ThrownItem>();

		internal void Update(ThrownItem thrownItem)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: 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_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Unknown result type (might be due to invalid IL or missing references)
			GrabbableObject item = thrownItem.GetItem();
			if (item.reachedFloorTarget || thrownItem.IsPanicking())
			{
				thrownItem.LandAndRemove();
				return;
			}
			float num = Utils.ItemScale(item);
			RaycastHit[] array = Physics.SphereCastAll(((Component)item).transform.position, num, ((Component)item).transform.forward, 0f, 11012424, (QueryTriggerInteraction)2);
			PlayerControllerB val2 = default(PlayerControllerB);
			IHittable val3 = default(IHittable);
			EnemyAI val4 = default(EnemyAI);
			for (int i = 0; i < array.Length; i++)
			{
				RaycastHit val = array[i];
				string name = ((Object)((RaycastHit)(ref val)).collider).name;
				if ((Object)(object)item == (Object)(object)((RaycastHit)(ref val)).collider)
				{
					Plugin.Logger.LogDebug((object)("skipping " + name + " (is itself)"));
					continue;
				}
				if (((Component)((RaycastHit)(ref val)).transform).gameObject.layer != 3 && ((Component)((RaycastHit)(ref val)).transform).gameObject.layer != 19)
				{
					Plugin.Logger.LogDebug((object)("skipping " + name + " (failed layer check)"));
					continue;
				}
				((Component)((RaycastHit)(ref val)).transform).TryGetComponent<PlayerControllerB>(ref val2);
				if ((Object)(object)thrownItem.GetThrower() == (Object)(object)val2)
				{
					Plugin.Logger.LogDebug((object)("skipping " + name + " (is the thrower)"));
					continue;
				}
				if (!((Component)((RaycastHit)(ref val)).transform).TryGetComponent<IHittable>(ref val3))
				{
					Plugin.Logger.LogInfo((object)("skipping " + name + " (not hittable)"));
					continue;
				}
				if (thrownItem.CheckIfHitOrAdd(val3))
				{
					Plugin.Logger.LogDebug((object)("skipping " + name + " (already been hit)"));
					continue;
				}
				float markiplier = thrownItem.GetMarkiplier();
				if ((Object)(object)val2 != (Object)null)
				{
					int num2 = (int)Math.Round(markiplier * 100f);
					Plugin.Logger.LogInfo((object)$"damaging a player {num2} ({val2.health}");
					Utils.DamagePlayer(val2, num2, ((Component)item).transform.forward, thrownItem.GetThrower());
					Plugin.Logger.LogInfo((object)$"they now have {val2.health} ({val2.isPlayerDead})");
					if (val2.isPlayerDead || val2.health == 0 || val2.health - num2 <= 0)
					{
						Plugin.Logger.LogInfo((object)"it killed them (lol)");
						continue;
					}
				}
				else
				{
					int num3 = (int)Math.Round(markiplier * 10f);
					Plugin.Logger.LogInfo((object)$"hitting something else {num3}");
					val3.Hit(num3, ((Component)item).transform.forward, thrownItem.GetThrower(), true);
				}
				if (((Component)((RaycastHit)(ref val)).collider).TryGetComponent<EnemyAI>(ref val4))
				{
					float num4 = markiplier * 5f;
					Plugin.Logger.LogInfo((object)$"stunning an enemy {num4}");
					val4.SetEnemyStunned(true, markiplier * 5f, thrownItem.GetThrower());
					if (val4.isEnemyDead || val4.enemyHP == 0)
					{
						Plugin.Logger.LogInfo((object)"it killed it");
						continue;
					}
				}
				Plugin.Logger.LogInfo((object)"dropping to floor");
				item.startFallingPosition = ((Component)item).transform.localPosition;
				item.FallToGround(false);
				thrownItem.LandAndRemove();
				break;
			}
		}
	}
}