Decompiled source of HarpoonHookshot v1.0.0

HarpoonHookshot.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("HarpoonHookshot")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+b5e6b68224d7401efb41cf902a7f7306087bd4fb")]
[assembly: AssemblyProduct("HarpoonHookshot")]
[assembly: AssemblyTitle("HarpoonHookshot")]
[assembly: AssemblyVersion("1.0.0.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 HarpoonHookshot
{
	internal static class FeatherFall
	{
		private const string EffectName = "HarpoonHookshotFeather";

		private static int hash;

		private static FieldInfo nameHash;

		private static bool lineOut;

		private static float groundTime;

		private static bool warned;

		internal static void Begin(Player player)
		{
			lineOut = true;
			groundTime = 0f;
			if ((Object)(object)player == (Object)null || !Ensure(out var _))
			{
				return;
			}
			SEMan sEMan = ((Character)player).GetSEMan();
			if (sEMan == null)
			{
				return;
			}
			if (!sEMan.HaveStatusEffect(hash))
			{
				sEMan.AddStatusEffect(hash, false, 0, 0f, (short)(-1));
			}
			StatusEffect statusEffect = sEMan.GetStatusEffect(hash);
			SE_Stats val = (SE_Stats)(object)((statusEffect is SE_Stats) ? statusEffect : null);
			if (!((Object)(object)val == (Object)null))
			{
				float value = HarpoonHookshotPlugin.FeatherSpeed.Value;
				val.m_maxMaxFallSpeed = (float.IsFinite(value) ? Mathf.Max(0f, value) : 7f);
				float num = HarpoonHookshotPlugin.FeatherDamage.Value;
				if (!float.IsFinite(num))
				{
					num = 0f;
				}
				val.m_fallDamageModifier = Mathf.Clamp(num, 0f, 1f) - 1f;
				((StatusEffect)val).m_ttl = 0f;
			}
		}

		internal static void LineEnded()
		{
			lineOut = false;
			groundTime = 0f;
		}

		internal static void Tick(float dt)
		{
			if (lineOut || hash == 0)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			SEMan sEMan = ((Character)localPlayer).GetSEMan();
			if (sEMan == null || !sEMan.HaveStatusEffect(hash))
			{
				return;
			}
			if (((Character)localPlayer).IsAttached() || ((Character)localPlayer).IsSwimming() || ((Character)localPlayer).IsDead())
			{
				sEMan.RemoveStatusEffect(hash, true);
			}
			else if (((Character)localPlayer).IsOnGround())
			{
				groundTime += dt;
				if (groundTime >= HarpoonHookshotPlugin.FeatherGroundSeconds.Value)
				{
					sEMan.RemoveStatusEffect(hash, true);
				}
			}
		}

		internal static void Remove()
		{
			lineOut = false;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null && hash != 0)
			{
				SEMan sEMan = ((Character)localPlayer).GetSEMan();
				if (sEMan != null)
				{
					sEMan.RemoveStatusEffect(hash, true);
				}
			}
		}

		private static bool Ensure(out StatusEffect effect)
		{
			effect = null;
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				return false;
			}
			hash = StringExtensionMethods.GetStableHashCode("HarpoonHookshotFeather");
			effect = ObjectDB.instance.GetStatusEffect(hash);
			if ((Object)(object)effect != (Object)null)
			{
				return true;
			}
			StatusEffect statusEffect = ObjectDB.instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode("SlowFall"));
			SE_Stats val = (SE_Stats)(object)((statusEffect is SE_Stats) ? statusEffect : null);
			if ((Object)(object)val == (Object)null)
			{
				if (!warned)
				{
					warned = true;
					HarpoonHookshotPlugin.Log.LogWarning((object)"HarpoonHookshot feather fall: SlowFall is not in ObjectDB.");
				}
				return false;
			}
			SE_Stats val2 = Object.Instantiate<SE_Stats>(val);
			((Object)val2).name = "HarpoonHookshotFeather";
			((StatusEffect)val2).m_ttl = 0f;
			if (nameHash == null)
			{
				nameHash = AccessTools.Field(typeof(StatusEffect), "m_nameHash");
			}
			nameHash?.SetValue(val2, hash);
			ObjectDB.instance.m_StatusEffects.Add((StatusEffect)(object)val2);
			effect = (StatusEffect)(object)val2;
			return true;
		}
	}
	[BepInPlugin("com.dfg.harpoonhookshot", "HarpoonHookshot", "1.0.0")]
	public class HarpoonHookshotPlugin : BaseUnityPlugin
	{
		public const string ModGUID = "com.dfg.harpoonhookshot";

		public const string ModName = "HarpoonHookshot";

		public const string ModVersion = "1.0.0";

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> Messages;

		internal static ConfigEntry<bool> Creatures;

		internal static ConfigEntry<bool> Players;

		internal static ConfigEntry<bool> Ships;

		internal static ConfigEntry<bool> Carts;

		internal static ConfigEntry<bool> Logs;

		internal static ConfigEntry<bool> Trees;

		internal static ConfigEntry<bool> Fish;

		internal static ConfigEntry<bool> Pieces;

		internal static ConfigEntry<bool> Destructibles;

		internal static ConfigEntry<bool> Items;

		internal static ConfigEntry<bool> Bosses;

		internal static ConfigEntry<bool> Leviathans;

		internal static ConfigEntry<bool> Terrain;

		internal static ConfigEntry<string> Whitelist;

		internal static ConfigEntry<string> Blacklist;

		internal static ConfigEntry<bool> Pulling;

		internal static ConfigEntry<float> ReelSpeed;

		internal static ConfigEntry<float> MaxMass;

		internal static ConfigEntry<float> StaminaDrain;

		internal static ConfigEntry<bool> FreeWinchOnShip;

		internal static ConfigEntry<float> Response;

		internal static ConfigEntry<float> MaxSpeed;

		internal static ConfigEntry<bool> PullUnderwater;

		internal static ConfigEntry<float> MaxDistance;

		internal static ConfigEntry<float> BreakExtra;

		internal static ConfigEntry<float> MinLength;

		internal static ConfigEntry<bool> DisableDamage;

		internal static ConfigEntry<float> Gravity;

		internal static ConfigEntry<float> Velocity;

		internal static ConfigEntry<bool> Feather;

		internal static ConfigEntry<float> FeatherSpeed;

		internal static ConfigEntry<float> FeatherDamage;

		internal static ConfigEntry<float> FeatherGroundSeconds;

		internal static ConfigEntry<KeyboardShortcut> ReelKey;

		internal static ConfigEntry<KeyboardShortcut> PayOutKey;

		internal static ConfigEntry<KeyboardShortcut> StopKey;

		internal static ConfigEntry<KeyboardShortcut> PullToKey;

		internal static ConfigEntry<bool> AlwaysPullTo;

		private static readonly HashSet<string> allowed = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static readonly HashSet<string> denied = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private Harmony harmony;

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			Bind();
			RebuildFilters();
			Whitelist.SettingChanged += OnFiltersChanged;
			Blacklist.SettingChanged += OnFiltersChanged;
			harmony = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "com.dfg.harpoonhookshot");
			Tether.Prepare((MonoBehaviour)(object)this);
			Log.LogInfo((object)"HarpoonHookshot 1.0.0 ready. The chitin harpoon hooks what it hits.");
		}

		private void Update()
		{
			if (!Enabled.Value)
			{
				if (Tether.IsActive)
				{
					Tether.Release("Released.");
				}
				FeatherFall.Tick(0f);
			}
			else
			{
				Tether.Tick(Time.deltaTime);
				FeatherFall.Tick(Time.deltaTime);
			}
		}

		private void FixedUpdate()
		{
			if (Enabled.Value)
			{
				Tether.ApplyPull();
			}
		}

		private void LateUpdate()
		{
			if (Enabled.Value)
			{
				Tether.ApplyPull();
				Tether.Draw();
			}
		}

		private void OnDestroy()
		{
			Tether.Release(null);
			FeatherFall.Remove();
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}

		private void OnFiltersChanged(object sender, EventArgs args)
		{
			RebuildFilters();
		}

		private void RebuildFilters()
		{
			Parse(Whitelist.Value, allowed);
			Parse(Blacklist.Value, denied);
		}

		private static void Parse(string value, HashSet<string> into)
		{
			into.Clear();
			if (string.IsNullOrWhiteSpace(value))
			{
				return;
			}
			string[] array = value.Split(new char[4] { ',', ';', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length != 0)
				{
					into.Add(text);
				}
			}
		}

		internal static bool PrefabAllowed(GameObject target)
		{
			if ((Object)(object)target == (Object)null)
			{
				return false;
			}
			string text = Utils.GetPrefabName(target);
			if (string.IsNullOrEmpty(text))
			{
				text = ((Object)target).name;
			}
			if (denied.Contains(text))
			{
				return false;
			}
			if (allowed.Count != 0)
			{
				return allowed.Contains(text);
			}
			return true;
		}

		internal static bool GameplayInput()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Invalid comparison between Unknown and I4
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				return false;
			}
			if (Menu.IsVisible() || Console.IsVisible() || InventoryGui.IsVisible() || TextInput.IsVisible())
			{
				return false;
			}
			if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
			{
				return false;
			}
			if ((Object)(object)Minimap.instance != (Object)null && (int)Minimap.instance.m_mode == 2)
			{
				return false;
			}
			return true;
		}

		internal static bool StopHeld()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (!GameplayInput())
			{
				return false;
			}
			KeyboardShortcut value = StopKey.Value;
			if (((KeyboardShortcut)(ref value)).IsPressed() || ZInput.GetButton("Block") || ZInput.GetButton("JoyBlock"))
			{
				return true;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				return ((Character)localPlayer).IsBlocking();
			}
			return false;
		}

		internal static bool PayOutHeld()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			if (!GameplayInput() || StopHeld())
			{
				return false;
			}
			KeyboardShortcut value;
			int num;
			if (!ZInput.GetButton("Use") && !ZInput.GetButton("JoyUse"))
			{
				value = ReelKey.Value;
				num = (((KeyboardShortcut)(ref value)).IsPressed() ? 1 : 0);
			}
			else
			{
				num = 1;
			}
			bool flag = (byte)num != 0;
			bool flag2 = ZInput.GetButton("Crouch") || ZInput.GetButton("JoyCrouch");
			value = PayOutKey.Value;
			if (!((KeyboardShortcut)(ref value)).IsPressed())
			{
				return flag && flag2;
			}
			return true;
		}

		internal static bool ReelHeld()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if (!GameplayInput() || StopHeld() || PayOutHeld())
			{
				return false;
			}
			if (!ZInput.GetButton("Use") && !ZInput.GetButton("JoyUse"))
			{
				KeyboardShortcut value = ReelKey.Value;
				return ((KeyboardShortcut)(ref value)).IsPressed();
			}
			return true;
		}

		internal static bool PullToHeld()
		{
			//IL_002b: 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 (AlwaysPullTo.Value)
			{
				return true;
			}
			if (!ZInput.GetButton("AltPlace") && !ZInput.GetButton("JoyAltPlace"))
			{
				KeyboardShortcut value = PullToKey.Value;
				return ((KeyboardShortcut)(ref value)).IsPressed();
			}
			return true;
		}

		internal static void Say(Player player, string text)
		{
			if (Messages.Value && !((Object)(object)player == (Object)null) && !string.IsNullOrEmpty(text))
			{
				((Character)player).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
		}

		private void Bind()
		{
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Expected O, but got Unknown
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Expected O, but got Unknown
			//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fa: Expected O, but got Unknown
			//IL_034d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0357: Expected O, but got Unknown
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0394: Expected O, but got Unknown
			//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f1: Expected O, but got Unknown
			//IL_0424: Unknown result type (might be due to invalid IL or missing references)
			//IL_042e: Expected O, but got Unknown
			//IL_0461: Unknown result type (might be due to invalid IL or missing references)
			//IL_046b: Expected O, but got Unknown
			//IL_04be: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c8: Expected O, but got Unknown
			//IL_04fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0505: Expected O, but got Unknown
			//IL_0558: Unknown result type (might be due to invalid IL or missing references)
			//IL_0562: Expected O, but got Unknown
			//IL_0595: Unknown result type (might be due to invalid IL or missing references)
			//IL_059f: Expected O, but got Unknown
			//IL_05d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_05dc: Expected O, but got Unknown
			//IL_05f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_062c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0668: Unknown result type (might be due to invalid IL or missing references)
			//IL_0696: Unknown result type (might be due to invalid IL or missing references)
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Enabled", true, "The chitin harpoon hooks objects and swings you to anything it cannot move.");
			Messages = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Messages", true, "Center-screen notes when the line hooks, pays out of reach, or is let go.");
			Creatures = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Targets", "Creatures", true, "Hook creatures and pull them. This replaces the vanilla creature rope so the line can be reeled.");
			Players = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Targets", "Players", true, "Other players keep the vanilla harpoon. Hold Use to reel that line in, Crouch+Use to pay it out.");
			Ships = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Targets", "Ships", true, "Hook ships. An empty ship is towed. A ship with a pilot is an anchor you swing to.");
			Carts = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Targets", "Carts", true, "Hook carts and pull them.");
			Logs = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Targets", "Tree logs", true, "Hook felled logs and pull them.");
			Trees = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Targets", "Trees", true, "A standing tree is an anchor you swing to.");
			Fish = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Targets", "Fish", true, "Hook fish and pull them in.");
			Pieces = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Targets", "Buildings", true, "A building piece is an anchor you swing to.");
			Destructibles = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Targets", "Destructibles", true, "Rocks, ore, and other destructibles are anchors you swing to.");
			Items = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Targets", "Items", true, "Hook dropped items and pull them in.");
			Bosses = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Targets", "Bosses", false, "Hook bosses. Off by default.");
			Leviathans = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Targets", "Leviathans", false, "A leviathan is an anchor. The mod never turns its body dynamic.");
			Terrain = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Targets", "Terrain", false, "Hook the ground itself and swing to that point. Off by default so a miss does not grab the floor.");
			Whitelist = ((BaseUnityPlugin)this).Config.Bind<string>("2 - Targets", "Prefab whitelist", "", "Exact prefab names, separated by commas. Empty allows every category above. Does not bypass those categories.");
			Blacklist = ((BaseUnityPlugin)this).Config.Bind<string>("2 - Targets", "Prefab blacklist", "", "Exact prefab names that never take a rope. The hit still lands. The blacklist wins over the whitelist.");
			Pulling = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Pull", "Enable pulling", true, "Hold Use (or T) to shorten the line. Hold Crouch+Use (or Ctrl+T) to pay it out. Block lets go.");
			ReelSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Pull", "Reel speed", 8f, new ConfigDescription("How fast the line shortens or lengthens, in metres per second.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>()));
			MaxMass = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Pull", "Maximum mass you can pull", 400f, new ConfigDescription("Heavier free bodies pull you to them instead. Ships are exempt.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 5000f), Array.Empty<object>()));
			StaminaDrain = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Pull", "Stamina drain", 8f, new ConfigDescription("Stamina per second while the line is taut. Zero spends none. Running out lets the line go.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 40f), Array.Empty<object>()));
			FreeWinchOnShip = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Pull", "Free winch aboard a ship", true, "Towing something while you are on a ship spends no stamina.");
			Response = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Pull", "Pull response", 6f, new ConfigDescription("Metres per second of pull added for each metre the line is stretched.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f), Array.Empty<object>()));
			MaxSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Pull", "Maximum pull speed", 12f, new ConfigDescription("Cap on the speed the line adds, in metres per second.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 30f), Array.Empty<object>()));
			PullUnderwater = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Pull", "Pull underwater", true, "When off, swinging toward a point below the waterline lets the line go.");
			MaxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Line", "Max distance", 45f, new ConfigDescription("The line cannot be longer than this, and a hit past it does not hook.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 120f), Array.Empty<object>()));
			BreakExtra = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Line", "Break slack", 12f, new ConfigDescription("The line snaps after it is stretched this far past its current length.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 40f), Array.Empty<object>()));
			MinLength = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Line", "Minimum length", 2f, new ConfigDescription("The shortest the line can be reeled. Getting closer does not snap it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 15f), Array.Empty<object>()));
			DisableDamage = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - Item", "Disable damage", false, "The harpoon hooks and deals no damage. Useful on deer, birds, and deathsquitos.");
			Gravity = ((BaseUnityPlugin)this).Config.Bind<float>("5 - Item", "Projectile gravity multiplier", 1f, new ConfigDescription("1 is the vanilla arc.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>()));
			Velocity = ((BaseUnityPlugin)this).Config.Bind<float>("5 - Item", "Projectile velocity multiplier", 1f, new ConfigDescription("1 is the vanilla throw.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 3f), Array.Empty<object>()));
			Feather = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Feather fall", "Enabled", true, "A copy of the feather-cape fall effect while the line is out, and briefly after it breaks.");
			FeatherSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("6 - Feather fall", "Maximum fall speed", 7f, new ConfigDescription("Downward speed cap in metres per second. Zero leaves the cap off.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>()));
			FeatherDamage = ((BaseUnityPlugin)this).Config.Bind<float>("6 - Feather fall", "Fall damage multiplier", 0f, new ConfigDescription("0 prevents this effect's fall damage. 1 leaves it unchanged.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			FeatherGroundSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("6 - Feather fall", "Seconds on the ground", 2f, new ConfigDescription("How long the effect lingers after the line is gone once you are standing on the ground.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			ReelKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("7 - Shortcuts", "Reel in", new KeyboardShortcut((KeyCode)116, Array.Empty<KeyCode>()), "Shorten the line. Use (E) does this too.");
			PayOutKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("7 - Shortcuts", "Pay out", new KeyboardShortcut((KeyCode)116, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Lengthen the line. Crouch+Use does this too.");
			StopKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("7 - Shortcuts", "Let go", new KeyboardShortcut((KeyCode)116, (KeyCode[])(object)new KeyCode[2]
			{
				(KeyCode)306,
				(KeyCode)304
			}), "Drop the line. Block (right mouse) does this too.");
			PullToKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("7 - Shortcuts", "Swing to target", new KeyboardShortcut((KeyCode)304, Array.Empty<KeyCode>()), "Hold this while the harpoon hits to swing yourself to the target, even when the target could have been pulled.");
			AlwaysPullTo = ((BaseUnityPlugin)this).Config.Bind<bool>("7 - Shortcuts", "Always swing to target", false, "Every hook swings you to the target.");
		}
	}
	internal static class HarpoonProjectile
	{
		internal static bool IsHarpoon(Projectile projectile, ItemData weapon)
		{
			if ((Object)(object)projectile != (Object)null && ((Object)projectile).name.StartsWith("projectile_chitinharpoon", StringComparison.Ordinal))
			{
				return true;
			}
			if (weapon != null && weapon.m_shared != null)
			{
				return weapon.m_shared.m_name == "$item_spear_chitin";
			}
			return false;
		}

		internal static bool IsLive(Projectile projectile, ZNetView view, ItemData weapon)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (HarpoonHookshotPlugin.Enabled != null && HarpoonHookshotPlugin.Enabled.Value && IsHarpoon(projectile, weapon))
			{
				Scene scene = ((Component)projectile).gameObject.scene;
				if (((Scene)(ref scene)).IsValid() && (Object)(object)view != (Object)null && view.IsValid())
				{
					return view.IsOwner();
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Projectile), "Setup")]
	internal static class Projectile_Setup_HarpoonHookshot
	{
		private static void Postfix(Projectile __instance, ZNetView ___m_nview, ItemData ___m_weapon, ref Vector3 ___m_vel)
		{
			//IL_0024: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			if (HarpoonProjectile.IsLive(__instance, ___m_nview, ___m_weapon))
			{
				__instance.m_gravity *= HarpoonHookshotPlugin.Gravity.Value;
				___m_vel *= HarpoonHookshotPlugin.Velocity.Value;
				if (HarpoonHookshotPlugin.DisableDamage.Value)
				{
					DamageTypes damage = __instance.m_damage;
					((DamageTypes)(ref damage)).Modify(0f);
					__instance.m_damage = damage;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Projectile), "FixedUpdate")]
	internal static class Projectile_FixedUpdate_HarpoonHookshotItems
	{
		private static FieldInfo maskField;

		private const int Untouched = int.MinValue;

		private static void Prefix(Projectile __instance, ZNetView ___m_nview, ItemData ___m_weapon, out int __state)
		{
			__state = int.MinValue;
			if (!HarpoonHookshotPlugin.Items.Value || !HarpoonProjectile.IsLive(__instance, ___m_nview, ___m_weapon))
			{
				return;
			}
			if (maskField == null)
			{
				maskField = AccessTools.Field(typeof(Projectile), "s_rayMaskSolids");
			}
			if (!(maskField == null))
			{
				int num = (int)maskField.GetValue(null);
				int mask = LayerMask.GetMask(new string[1] { "item" });
				if ((num & mask) == 0)
				{
					__state = num;
					maskField.SetValue(null, num | mask);
				}
			}
		}

		private static void Finalizer(int __state)
		{
			if (__state != int.MinValue && !(maskField == null))
			{
				maskField.SetValue(null, __state);
			}
		}
	}
	[HarmonyPatch(typeof(Projectile), "OnHit")]
	internal static class Projectile_OnHit_HarpoonHookshot
	{
		private sealed class Hit
		{
			public int Hash;

			public bool Suppressed;

			public bool Attach;

			public GameObject Target;

			public Vector3 Point;

			public Collider Collider;
		}

		private static void Prefix(Projectile __instance, Collider collider, Vector3 hitPoint, bool water, Character ___m_owner, bool ___m_didHit, ZNetView ___m_nview, ItemData ___m_weapon, ref int ___m_statusEffectHash, out Hit __state)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			__state = null;
			if (water || ___m_didHit || (Object)(object)collider == (Object)null || !HarpoonProjectile.IsLive(__instance, ___m_nview, ___m_weapon))
			{
				return;
			}
			Player val = (Player)(object)((___m_owner is Player) ? ___m_owner : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			GameObject val2 = Projectile.FindHitObject(collider) ?? ((Component)collider).gameObject;
			if ((Object)(object)val2 == (Object)null || (Object)(object)val2.GetComponentInParent<Character>() == (Object)(object)val)
			{
				return;
			}
			__state = new Hit
			{
				Hash = ___m_statusEffectHash,
				Target = val2,
				Point = hitPoint,
				Collider = collider
			};
			bool pullsObject;
			if (Tether.IsPlayerTarget(val2))
			{
				if (!HarpoonHookshotPlugin.Players.Value || !HarpoonHookshotPlugin.PrefabAllowed(val2))
				{
					___m_statusEffectHash = 0;
					__state.Suppressed = true;
				}
			}
			else if (Tether.WantsCustomHook(val2, collider, out pullsObject))
			{
				float num = Vector3.Distance(hitPoint, ((Component)val).transform.position);
				if (float.IsFinite(num) && !(num > HarpoonHookshotPlugin.MaxDistance.Value))
				{
					___m_statusEffectHash = 0;
					__state.Suppressed = true;
					__state.Attach = true;
				}
			}
		}

		private static void Postfix(Projectile __instance, Hit __state, bool ___m_didHit, bool ___m_didBounce, Character ___m_owner)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if (!(__state == null || !__state.Attach || (Object)(object)__instance == (Object)null || !___m_didHit || ___m_didBounce))
			{
				Player val = (Player)(object)((___m_owner is Player) ? ___m_owner : null);
				if (!((Object)(object)val == (Object)null) && !((Object)(object)__state.Target == (Object)null))
				{
					Tether.Begin(val, __state.Target, __state.Point, __state.Collider);
				}
			}
		}

		private static void Finalizer(Projectile __instance, Hit __state, ref int ___m_statusEffectHash)
		{
			if (__state != null && __state.Suppressed && (Object)(object)__instance != (Object)null)
			{
				___m_statusEffectHash = __state.Hash;
			}
		}
	}
	[HarmonyPatch(typeof(SE_Harpooned), "UpdateStatusEffect")]
	internal static class SE_Harpooned_Update_HarpoonHookshotReel
	{
		private static void Postfix(float dt, Character ___m_attacker, ref float ___m_baseDistance)
		{
			if (HarpoonHookshotPlugin.Enabled.Value && HarpoonHookshotPlugin.Pulling.Value && HarpoonHookshotPlugin.Players.Value && !((Object)(object)___m_attacker == (Object)null) && !((Object)(object)___m_attacker != (Object)(object)Player.m_localPlayer) && !Tether.IsActive)
			{
				if (HarpoonHookshotPlugin.PayOutHeld())
				{
					___m_baseDistance += HarpoonHookshotPlugin.ReelSpeed.Value * dt;
				}
				else if (HarpoonHookshotPlugin.ReelHeld())
				{
					___m_baseDistance -= HarpoonHookshotPlugin.ReelSpeed.Value * dt;
				}
				___m_baseDistance = Mathf.Max(___m_baseDistance, HarpoonHookshotPlugin.MinLength.Value);
			}
		}
	}
	[HarmonyPatch(typeof(SE_Harpooned), "IsDone")]
	internal static class SE_Harpooned_IsDone_HarpoonHookshotStop
	{
		private static void Postfix(Character ___m_attacker, ref bool ___m_broken, ref bool __result)
		{
			if (!__result && HarpoonHookshotPlugin.Enabled.Value && !((Object)(object)___m_attacker != (Object)(object)Player.m_localPlayer) && HarpoonHookshotPlugin.StopHeld())
			{
				___m_broken = true;
				__result = true;
			}
		}
	}
	internal static class Tether
	{
		private static Player attacker;

		private static GameObject target;

		private static Transform anchor;

		private static Vector3 localPoint;

		private static Rigidbody body;

		private static ZNetView view;

		private static Character creature;

		private static Ship ship;

		private static bool pullSelf;

		private static bool claimed;

		private static float lineLength;

		private static float minLength;

		private static float age;

		private static string label;

		private static LineRenderer line;

		private static MethodInfo shipHasPilot;

		internal static bool IsActive { get; private set; }

		internal static void Prepare(MonoBehaviour host)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)line != (Object)null))
			{
				GameObject val = new GameObject("HarpoonHookshotLine");
				val.transform.SetParent(((Component)host).transform, false);
				line = val.AddComponent<LineRenderer>();
				line.positionCount = 3;
				line.useWorldSpace = true;
				((Renderer)line).shadowCastingMode = (ShadowCastingMode)0;
				((Renderer)line).receiveShadows = false;
				line.startWidth = 0.045f;
				line.endWidth = 0.045f;
				((Renderer)line).enabled = false;
				shipHasPilot = AccessTools.Method(typeof(Ship), "HaveControllingPlayer", (Type[])null, (Type[])null);
			}
		}

		internal static bool WantsCustomHook(GameObject hit, Collider collider, out bool pullsObject)
		{
			pullsObject = false;
			if ((Object)(object)hit == (Object)null || HasBlocker(hit))
			{
				return false;
			}
			if (!HarpoonHookshotPlugin.PrefabAllowed(hit))
			{
				return false;
			}
			Character componentInParent = hit.GetComponentInParent<Character>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				if (componentInParent.IsPlayer())
				{
					return false;
				}
				if (componentInParent.IsBoss() && !HarpoonHookshotPlugin.Bosses.Value)
				{
					return false;
				}
				if (!HarpoonHookshotPlugin.Creatures.Value)
				{
					return false;
				}
				pullsObject = true;
				return true;
			}
			if ((Object)(object)hit.GetComponentInParent<Ship>() != (Object)null)
			{
				pullsObject = true;
				return HarpoonHookshotPlugin.Ships.Value;
			}
			if ((Object)(object)hit.GetComponentInParent<Vagon>() != (Object)null)
			{
				pullsObject = true;
				return HarpoonHookshotPlugin.Carts.Value;
			}
			if ((Object)(object)hit.GetComponentInParent<TreeLog>() != (Object)null)
			{
				pullsObject = true;
				return HarpoonHookshotPlugin.Logs.Value;
			}
			if ((Object)(object)hit.GetComponentInParent<Fish>() != (Object)null)
			{
				pullsObject = true;
				return HarpoonHookshotPlugin.Fish.Value;
			}
			if ((Object)(object)hit.GetComponentInParent<ItemDrop>() != (Object)null)
			{
				pullsObject = true;
				return HarpoonHookshotPlugin.Items.Value;
			}
			if ((Object)(object)hit.GetComponentInParent<TreeBase>() != (Object)null)
			{
				return HarpoonHookshotPlugin.Trees.Value;
			}
			if ((Object)(object)hit.GetComponentInParent<Leviathan>() != (Object)null)
			{
				return HarpoonHookshotPlugin.Leviathans.Value;
			}
			if ((Object)(object)hit.GetComponentInParent<MineRock5>() != (Object)null || (Object)(object)hit.GetComponentInParent<MineRock>() != (Object)null || (Object)(object)hit.GetComponentInParent<Destructible>() != (Object)null)
			{
				return HarpoonHookshotPlugin.Destructibles.Value;
			}
			if ((Object)(object)hit.GetComponentInParent<Piece>() != (Object)null)
			{
				return HarpoonHookshotPlugin.Pieces.Value;
			}
			if (HarpoonHookshotPlugin.Terrain.Value && (Object)(object)collider != (Object)null && ((object)collider).GetType().Name == "TerrainCollider")
			{
				return true;
			}
			return false;
		}

		internal static bool IsPlayerTarget(GameObject hit)
		{
			Character val = (((Object)(object)hit != (Object)null) ? hit.GetComponentInParent<Character>() : null);
			if ((Object)(object)val != (Object)null)
			{
				return val.IsPlayer();
			}
			return false;
		}

		internal static void Begin(Player player, GameObject hit, Vector3 point, Collider collider)
		{
			//IL_0035: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || (Object)(object)hit == (Object)null)
			{
				return;
			}
			Release(null);
			attacker = player;
			target = hit;
			anchor = hit.transform;
			localPoint = anchor.InverseTransformPoint(point);
			creature = hit.GetComponentInParent<Character>();
			ship = hit.GetComponentInParent<Ship>();
			body = hit.GetComponentInParent<Rigidbody>() ?? collider.attachedRigidbody;
			view = hit.GetComponentInParent<ZNetView>();
			label = NameOf(hit);
			age = 0f;
			claimed = false;
			float num = Vector3.Distance(((Component)player).transform.position, point);
			if (!float.IsFinite(num) || num > HarpoonHookshotPlugin.MaxDistance.Value)
			{
				Clear();
				HarpoonHookshotPlugin.Say(player, "Too far.");
				return;
			}
			pullSelf = HarpoonHookshotPlugin.PullToHeld() || !CanDrag();
			if (!pullSelf && (Object)(object)view != (Object)null && view.IsValid() && !view.IsOwner())
			{
				view.ClaimOwnership();
				claimed = true;
			}
			lineLength = Mathf.Clamp(num, HarpoonHookshotPlugin.MinLength.Value, HarpoonHookshotPlugin.MaxDistance.Value);
			minLength = (((Object)(object)ship != (Object)null && !pullSelf) ? Mathf.Max(6f, HarpoonHookshotPlugin.MinLength.Value) : HarpoonHookshotPlugin.MinLength.Value);
			IsActive = true;
			StyleLine();
			if (HarpoonHookshotPlugin.Feather.Value)
			{
				FeatherFall.Begin(player);
			}
			HarpoonHookshotPlugin.Log.LogInfo((object)("HarpoonHookshot hooked " + label + (pullSelf ? " (swing)" : " (pull)") + " at " + num.ToString("0.0") + " m."));
			HarpoonHookshotPlugin.Say(player, (pullSelf ? "Swinging to " : "Hooked ") + label + ".");
		}

		internal static void Tick(float dt)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			if (!IsActive)
			{
				return;
			}
			age += dt;
			if (!StillThere())
			{
				Release("The line goes slack.");
				return;
			}
			Vector3 val = AnchorPoint();
			float num = Vector3.Distance(((Component)attacker).transform.position, val);
			if (!float.IsFinite(num))
			{
				Release(null);
				return;
			}
			float num2 = lineLength + HarpoonHookshotPlugin.BreakExtra.Value;
			if (num > num2 || num > HarpoonHookshotPlugin.MaxDistance.Value + HarpoonHookshotPlugin.BreakExtra.Value)
			{
				Release("The line snaps.");
				return;
			}
			if (pullSelf && !HarpoonHookshotPlugin.PullUnderwater.Value && BelowWater(val))
			{
				Release("The line will not pull underwater.");
				return;
			}
			if (((Character)attacker).IsDead() || ((Character)attacker).IsTeleporting() || ((Character)attacker).InCutscene())
			{
				Release(null);
				return;
			}
			if (pullSelf && ((Character)attacker).IsAttached())
			{
				Release("Let go.");
				return;
			}
			if ((Object)(object)creature != (Object)null && creature.IsDead())
			{
				Release("Released.");
				return;
			}
			Ship localShip = Ship.GetLocalShip();
			if ((Object)(object)ship != (Object)null && (Object)(object)localShip == (Object)(object)ship)
			{
				Release("The line will not pull the ship you are standing on.");
				return;
			}
			if (age > 0.4f && HarpoonHookshotPlugin.StopHeld())
			{
				Release("Released.");
				return;
			}
			if (HarpoonHookshotPlugin.Pulling.Value)
			{
				if (HarpoonHookshotPlugin.PayOutHeld())
				{
					lineLength += HarpoonHookshotPlugin.ReelSpeed.Value * dt;
				}
				else if (HarpoonHookshotPlugin.ReelHeld())
				{
					lineLength -= HarpoonHookshotPlugin.ReelSpeed.Value * dt;
				}
				lineLength = Mathf.Clamp(lineLength, minLength, HarpoonHookshotPlugin.MaxDistance.Value);
			}
			if (!pullSelf && claimed && age > 1.5f && (Object)(object)view != (Object)null && view.IsValid() && !view.IsOwner())
			{
				pullSelf = true;
				HarpoonHookshotPlugin.Say(attacker, "Swinging to " + label + ".");
			}
			if (num > lineLength + 0.15f)
			{
				Drain(dt);
			}
		}

		internal static void ApplyPull()
		{
			//IL_0091: 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_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: 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_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: 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_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: 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_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			if (!IsActive || !StillThere() || Menu.IsVisible() || (!pullSelf && (Object)(object)view != (Object)null && view.IsValid() && !view.IsOwner()))
			{
				return;
			}
			Rigidbody val = (pullSelf ? ((Component)attacker).GetComponent<Rigidbody>() : body);
			if ((Object)(object)val == (Object)null || val.isKinematic)
			{
				return;
			}
			Vector3 val2 = (pullSelf ? AnchorPoint() : (((Component)attacker).transform.position + Vector3.up)) - val.position;
			float magnitude = ((Vector3)(ref val2)).magnitude;
			if (magnitude <= lineLength || magnitude < 0.05f || !float.IsFinite(magnitude))
			{
				return;
			}
			Vector3 val3 = val2 / magnitude;
			float num = Mathf.Clamp((magnitude - lineLength) * HarpoonHookshotPlugin.Response.Value, 0f, HarpoonHookshotPlugin.MaxSpeed.Value);
			if (!pullSelf && (Object)(object)ship == (Object)null)
			{
				num *= Mathf.Clamp(60f / Mathf.Max(1f, val.mass), 0.2f, 1f);
			}
			else if (!pullSelf && (Object)(object)ship != (Object)null)
			{
				num *= 0.45f;
			}
			Vector3 linearVelocity = val.linearVelocity;
			float num2 = Vector3.Dot(linearVelocity, val3);
			if (!(num2 >= num))
			{
				Vector3 val4 = val3 * (num - num2);
				if (!pullSelf && (Object)(object)ship != (Object)null && val4.y > 0f)
				{
					val4.y = 0f;
				}
				linearVelocity += val4;
				if (pullSelf || (Object)(object)creature != (Object)null)
				{
					linearVelocity = Vector3.ClampMagnitude(linearVelocity, HarpoonHookshotPlugin.MaxSpeed.Value);
				}
				val.linearVelocity = linearVelocity;
			}
		}

		internal static void Draw()
		{
			//IL_0028: 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_002e: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: 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)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_0093: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)line == (Object)null))
			{
				if (!IsActive || !StillThere())
				{
					((Renderer)line).enabled = false;
					return;
				}
				Vector3 val = HandPoint();
				Vector3 val2 = AnchorPoint();
				Vector3 val3 = (val + val2) * 0.5f;
				float num = Mathf.Clamp(lineLength - Vector3.Distance(val, val2), 0f, 3f);
				val3.y -= num * 0.45f;
				line.SetPosition(0, val);
				line.SetPosition(1, val3);
				line.SetPosition(2, val2);
				((Renderer)line).enabled = true;
			}
		}

		internal static void Release(string message)
		{
			Player player = attacker;
			bool isActive = IsActive;
			Clear();
			if (isActive)
			{
				if ((Object)(object)line != (Object)null)
				{
					((Renderer)line).enabled = false;
				}
				FeatherFall.LineEnded();
				if (!string.IsNullOrEmpty(message))
				{
					HarpoonHookshotPlugin.Log.LogInfo((object)("HarpoonHookshot " + message));
					HarpoonHookshotPlugin.Say(player, message);
				}
			}
		}

		private static void Clear()
		{
			IsActive = false;
			attacker = null;
			target = null;
			anchor = null;
			body = null;
			view = null;
			creature = null;
			ship = null;
			claimed = false;
			label = null;
			age = 0f;
		}

		private static bool StillThere()
		{
			if ((Object)(object)attacker != (Object)null && (Object)(object)attacker == (Object)(object)Player.m_localPlayer && (Object)(object)anchor != (Object)null && (Object)(object)target != (Object)null)
			{
				return target.activeInHierarchy;
			}
			return false;
		}

		private static bool CanDrag()
		{
			if ((Object)(object)body == (Object)null || body.isKinematic)
			{
				return false;
			}
			if ((Object)(object)ship != (Object)null)
			{
				return !PilotAboard(ship);
			}
			return body.mass <= HarpoonHookshotPlugin.MaxMass.Value;
		}

		private static bool PilotAboard(Ship targetShip)
		{
			if (shipHasPilot == null || (Object)(object)targetShip == (Object)null)
			{
				return false;
			}
			try
			{
				return (bool)shipHasPilot.Invoke(targetShip, null);
			}
			catch
			{
				return true;
			}
		}

		private static void Drain(float dt)
		{
			float value = HarpoonHookshotPlugin.StaminaDrain.Value;
			if (!(value <= 0f) && !((Object)(object)attacker == (Object)null) && (!HarpoonHookshotPlugin.FreeWinchOnShip.Value || pullSelf || !((Character)attacker).IsAttachedToShip()))
			{
				float num = value * dt;
				if (!((Character)attacker).HaveStamina(num))
				{
					Release("Too tired. The line slips.");
				}
				else
				{
					((Character)attacker).UseStamina(num);
				}
			}
		}

		private static Vector3 AnchorPoint()
		{
			//IL_0018: 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_000d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)anchor == (Object)null)
			{
				return localPoint;
			}
			return anchor.TransformPoint(localPoint);
		}

		private static Vector3 HandPoint()
		{
			//IL_006d: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			VisEquipment val = (((Object)(object)attacker != (Object)null) ? ((Humanoid)attacker).GetVisEquipment() : null);
			if ((Object)(object)val != (Object)null && (Object)(object)val.m_leftHand != (Object)null && ((Component)val.m_leftHand).gameObject.activeInHierarchy)
			{
				return val.m_leftHand.position;
			}
			if ((Object)(object)attacker == (Object)null)
			{
				return Vector3.zero;
			}
			return ((Component)attacker).transform.position + Vector3.up * 1.2f;
		}

		private static bool BelowWater(Vector3 point)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZoneSystem.instance != (Object)null)
			{
				return point.y < ZoneSystem.instance.m_waterLevel;
			}
			return false;
		}

		private static void StyleLine()
		{
			//IL_00c7: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			if ((Object)(object)line == (Object)null || (Object)(object)((Renderer)line).sharedMaterial != (Object)null)
			{
				return;
			}
			Material val = null;
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab("vfx_Harpooned");
				LineRenderer val2 = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<LineRenderer>() : null);
				if ((Object)(object)val2 != (Object)null)
				{
					val = ((Renderer)val2).sharedMaterial;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Shader val3 = Shader.Find("Sprites/Default");
				if ((Object)(object)val3 == (Object)null)
				{
					val3 = Shader.Find("Hidden/Internal-Colored");
				}
				if ((Object)(object)val3 != (Object)null)
				{
					val = new Material(val3);
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				((Renderer)line).sharedMaterial = val;
			}
			line.startColor = new Color(0.86f, 0.8f, 0.68f, 1f);
			line.endColor = new Color(0.72f, 0.66f, 0.52f, 1f);
		}

		private static string NameOf(GameObject hit)
		{
			HoverText componentInParent = hit.GetComponentInParent<HoverText>();
			if ((Object)(object)componentInParent != (Object)null && !string.IsNullOrEmpty(componentInParent.m_text))
			{
				return Local(componentInParent.m_text);
			}
			if ((Object)(object)creature != (Object)null && !string.IsNullOrEmpty(creature.m_name))
			{
				return Local(creature.m_name);
			}
			ItemDrop componentInParent2 = hit.GetComponentInParent<ItemDrop>();
			if ((Object)(object)componentInParent2 != (Object)null && componentInParent2.m_itemData != null && componentInParent2.m_itemData.m_shared != null)
			{
				return Local(componentInParent2.m_itemData.m_shared.m_name);
			}
			Piece componentInParent3 = hit.GetComponentInParent<Piece>();
			if ((Object)(object)componentInParent3 != (Object)null && !string.IsNullOrEmpty(componentInParent3.m_name))
			{
				return Local(componentInParent3.m_name);
			}
			string prefabName = Utils.GetPrefabName(hit);
			if (!string.IsNullOrEmpty(prefabName))
			{
				return prefabName;
			}
			return "target";
		}

		private static string Local(string text)
		{
			if (Localization.instance != null)
			{
				text = Localization.instance.Localize(text);
			}
			return text;
		}

		private static bool HasBlocker(GameObject hit)
		{
			MonoBehaviour[] componentsInParent = hit.GetComponentsInParent<MonoBehaviour>(true);
			foreach (MonoBehaviour val in componentsInParent)
			{
				if ((Object)(object)val != (Object)null && ((object)val).GetType().Name == "GrapplingBlocker")
				{
					return true;
				}
			}
			return false;
		}
	}
}