Decompiled source of GruffyAICompanion v1.2.1

GruffyAICompanion.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using MenuLib;
using MenuLib.MonoBehaviors;
using Newtonsoft.Json;
using Photon.Pun;
using Photon.Realtime;
using Strobotnik.Klattersynth;
using TMPro;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("GruffyAICompanion")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("GruffyAICompanion")]
[assembly: AssemblyTitle("GruffyAICompanion")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace GruffyAICompanion
{
	internal class GruffyBody : MonoBehaviour
	{
		private Animator animator;

		private readonly HashSet<string> animParams = new HashSet<string>();

		private Transform jaw;

		private float footOffset;

		private float visualY;

		private bool visualYInitialized;

		private float yaw;

		private float previousYaw;

		private float turningTimer;

		private bool sprintingPrevious;

		private float mouthLoudness;

		private GruffyRig rig;

		private const float RollRadius = 0.45f;

		private float tumbleTimer;

		private float rollAngle;

		private float turnDifference;

		private float turnDirection;

		private float previousTargetYaw;

		internal Action<float> Tumbled;

		internal Transform Visual { get; private set; }

		internal Transform HeadPoint { get; private set; }

		internal Transform HandPoint { get; private set; }

		internal float Yaw => yaw;

		internal Vector3 LastPosition { get; private set; }

		internal float LastTargetYaw { get; private set; }

		internal Vector3 LastVelocity { get; private set; }

		internal bool LastSprinting { get; private set; }

		internal bool LastCrouching { get; private set; }

		internal bool LastGrabbing { get; private set; }

		internal Vector3? LastLook { get; private set; }

		internal Vector3? LastGrabPoint { get; private set; }

		internal bool IsVisible
		{
			get
			{
				if ((Object)(object)Visual != (Object)null)
				{
					return ((Component)Visual).gameObject.activeSelf;
				}
				return false;
			}
		}

		internal Vector3 Forward => Quaternion.Euler(0f, yaw, 0f) * Vector3.forward;

		internal bool IsTumbling => tumbleTimer > 0f;

		internal bool Crawl { get; set; }

		internal bool Build(PlayerAvatar source, Color? tint, out string error)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_0362: Unknown result type (might be due to invalid IL or missing references)
			//IL_036c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0371: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: 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_03d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0403: Unknown result type (might be due to invalid IL or missing references)
			//IL_040e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0413: Unknown result type (might be due to invalid IL or missing references)
			//IL_0429: Unknown result type (might be due to invalid IL or missing references)
			//IL_0458: Unknown result type (might be due to invalid IL or missing references)
			//IL_039e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0484: Unknown result type (might be due to invalid IL or missing references)
			//IL_04af: Unknown result type (might be due to invalid IL or missing references)
			error = null;
			PlayerAvatarVisuals val = (((Object)(object)source != (Object)null) ? source.playerAvatarVisuals : null);
			if ((Object)(object)val == (Object)null)
			{
				error = "the local player has no visuals to copy";
				return false;
			}
			GameObject val2 = new GameObject("GruffyBuildHolder");
			val2.SetActive(false);
			GameObject val3;
			try
			{
				val3 = Object.Instantiate<GameObject>(((Component)val).gameObject, val2.transform);
			}
			catch (Exception ex)
			{
				Object.Destroy((Object)(object)val2);
				error = "couldn't copy the player model: " + ex.Message;
				return false;
			}
			((Object)val3).name = "Gruffy Visuals";
			val3.SetActive(true);
			PlayerAvatarVisuals component = val3.GetComponent<PlayerAvatarVisuals>();
			PlayerAvatarTalkAnimation componentInChildren = val3.GetComponentInChildren<PlayerAvatarTalkAnimation>(true);
			PlayerAvatarRightArm componentInChildren2 = val3.GetComponentInChildren<PlayerAvatarRightArm>(true);
			jaw = (((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren.objectToRotate != (Object)null) ? componentInChildren.objectToRotate.transform : null);
			HeadPoint = ((!((Object)(object)component != (Object)null)) ? null : (((Object)(object)component.TTSTransform != (Object)null) ? component.TTSTransform : component.headLookAtTransform));
			HandPoint = ((!((Object)(object)componentInChildren2 != (Object)null)) ? null : (((Object)(object)componentInChildren2.grabberTransform != (Object)null) ? componentInChildren2.grabberTransform : componentInChildren2.grabberClawParent));
			rig = new GruffyRig();
			rig.Capture(component, componentInChildren2, val3.GetComponentInChildren<PlayerAvatarLeftArm>(true), val3.GetComponentInChildren<PlayerEyes>(true));
			if (!Plugin.CopyPlayerCosmetics.Value)
			{
				RemoveCosmetics(val3, component);
			}
			List<PlayerMaterial> list = new List<PlayerMaterial>();
			PlayerMaterial[] componentsInChildren = val3.GetComponentsInChildren<PlayerMaterial>(true);
			foreach (PlayerMaterial val4 in componentsInChildren)
			{
				if (val4.tintable && (Object)(object)((Component)val4).GetComponentInParent<Cosmetic>(true) == (Object)null)
				{
					list.Add(val4);
				}
			}
			int num = LayerMask.NameToLayer("PlayerVisualsLocal");
			int num2 = LayerMask.NameToLayer("TopLayer");
			int num3 = ((Component)val).gameObject.layer;
			if (num3 == num)
			{
				num3 = LayerMask.NameToLayer("Default");
			}
			Transform[] componentsInChildren2 = val3.GetComponentsInChildren<Transform>(true);
			foreach (Transform val5 in componentsInChildren2)
			{
				if ((Object)(object)val5 != (Object)(object)val3.transform && ((Component)val5).gameObject.layer == num2)
				{
					((Component)val5).gameObject.SetActive(false);
				}
			}
			if (tint.HasValue)
			{
				ApplyTint(list, tint.Value);
			}
			StripComponents(val3, rig.GrabberLight);
			Renderer[] componentsInChildren3 = val3.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val6 in componentsInChildren3)
			{
				if (!(val6 is ParticleSystemRenderer))
				{
					val6.shadowCastingMode = (ShadowCastingMode)1;
					if (((Component)val6).gameObject.layer == num || ((Component)val6).gameObject.layer == num2)
					{
						((Component)val6).gameObject.layer = num3;
					}
				}
			}
			animator = val3.GetComponent<Animator>();
			if ((Object)(object)animator == (Object)null)
			{
				Object.Destroy((Object)(object)val2);
				Object.Destroy((Object)(object)val3);
				error = "the player model has no Animator";
				return false;
			}
			animator.cullingMode = (AnimatorCullingMode)0;
			animator.applyRootMotion = false;
			AnimatorControllerParameter[] parameters = animator.parameters;
			foreach (AnimatorControllerParameter val7 in parameters)
			{
				animParams.Add(val7.name);
			}
			val3.AddComponent<GruffyAnimationEvents>();
			footOffset = 0f;
			Vector3 position = ((Component)val).transform.position;
			RaycastHit val8 = default(RaycastHit);
			if (Physics.Raycast(position + Vector3.up * 0.5f, Vector3.down, ref val8, 3f, LayerMask.GetMask(new string[1] { "Default" }), (QueryTriggerInteraction)1))
			{
				footOffset = Mathf.Clamp(position.y - ((RaycastHit)(ref val8)).point.y, -0.2f, 0.6f);
			}
			Vector3 lossyScale = ((Component)val).transform.lossyScale;
			val3.transform.SetParent(((Component)this).transform, false);
			val3.transform.localScale = lossyScale;
			val3.transform.position = ((Component)this).transform.position + Vector3.up * footOffset;
			val3.transform.rotation = ((Component)this).transform.rotation;
			Object.Destroy((Object)(object)val2);
			rig.Activate();
			Visual = val3.transform;
			yaw = (previousYaw = ((Component)this).transform.eulerAngles.y);
			if ((Object)(object)HeadPoint == (Object)null)
			{
				Transform transform = new GameObject("GruffyHeadPoint").transform;
				transform.SetParent(Visual, false);
				transform.localPosition = new Vector3(0f, 1.5f, 0f);
				HeadPoint = transform;
			}
			if ((Object)(object)HandPoint == (Object)null)
			{
				HandPoint = HeadPoint;
			}
			if (Plugin.HeadLight.Value)
			{
				AddHeadLight();
			}
			Plugin.Debug(string.Format("Body built: animator params [{0}], footOffset {1:0.00}, jaw {2}, hand {3}", string.Join(", ", animParams), footOffset, (Object)(object)jaw != (Object)null, (Object)(object)HandPoint != (Object)null));
			return true;
		}

		private static void RemoveCosmetics(GameObject clone, PlayerAvatarVisuals visuals)
		{
			Cosmetic[] componentsInChildren = clone.GetComponentsInChildren<Cosmetic>(true);
			foreach (Cosmetic val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)((Component)val).gameObject);
				}
			}
			PlayerCosmetics val2 = (((Object)(object)visuals != (Object)null) ? visuals.playerCosmetics : null);
			if ((Object)(object)val2 == (Object)null || !((Component)val2).transform.IsChildOf(clone.transform) || val2.cosmeticParents == null)
			{
				return;
			}
			foreach (CosmeticParent cosmeticParent in val2.cosmeticParents)
			{
				if (cosmeticParent?.baseMeshes == null)
				{
					continue;
				}
				foreach (Transform baseMesh in cosmeticParent.baseMeshes)
				{
					if (!((Object)(object)baseMesh == (Object)null))
					{
						((Component)baseMesh).gameObject.SetActive(true);
						Renderer[] componentsInChildren2 = ((Component)baseMesh).GetComponentsInChildren<Renderer>(true);
						for (int i = 0; i < componentsInChildren2.Length; i++)
						{
							componentsInChildren2[i].enabled = true;
						}
					}
				}
			}
		}

		private static void ApplyTint(List<PlayerMaterial> targets, Color color)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Invalid comparison between Unknown and I4
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Invalid comparison between Unknown and I4
			//IL_0075: 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_0081: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Invalid comparison between Unknown and I4
			//IL_00bf: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			int num = Shader.PropertyToID("_AlbedoColor");
			int num2 = Shader.PropertyToID("_EmissionColor");
			int num3 = Shader.PropertyToID("_FresnelColor");
			foreach (PlayerMaterial target in targets)
			{
				Renderer component = ((Component)target).GetComponent<Renderer>();
				if (!((Object)(object)component == (Object)null))
				{
					Material material = component.material;
					if (((int)target.tintType == 0 || (int)target.tintType == 2) && material.HasProperty(num))
					{
						material.SetColor(num, new Color(color.r, color.g, color.b, material.GetColor(num).a));
					}
					if (((int)target.tintType == 1 || (int)target.tintType == 2) && material.HasProperty(num2))
					{
						material.SetColor(num2, new Color(color.r, color.g, color.b, material.GetColor(num2).a));
					}
					if (target.tintFresnel && material.HasProperty(num3))
					{
						material.SetColor(num3, color);
					}
				}
			}
		}

		private static void StripComponents(GameObject clone, Light keepLight)
		{
			for (int i = 0; i < 4; i++)
			{
				MonoBehaviour[] componentsInChildren = clone.GetComponentsInChildren<MonoBehaviour>(true);
				if (componentsInChildren.Length == 0)
				{
					break;
				}
				for (int num = componentsInChildren.Length - 1; num >= 0; num--)
				{
					if ((Object)(object)componentsInChildren[num] != (Object)null)
					{
						Object.DestroyImmediate((Object)(object)componentsInChildren[num]);
					}
				}
			}
			Joint[] componentsInChildren2 = clone.GetComponentsInChildren<Joint>(true);
			for (int j = 0; j < componentsInChildren2.Length; j++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren2[j]);
			}
			Collider[] componentsInChildren3 = clone.GetComponentsInChildren<Collider>(true);
			for (int j = 0; j < componentsInChildren3.Length; j++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren3[j]);
			}
			Rigidbody[] componentsInChildren4 = clone.GetComponentsInChildren<Rigidbody>(true);
			for (int j = 0; j < componentsInChildren4.Length; j++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren4[j]);
			}
			Camera[] componentsInChildren5 = clone.GetComponentsInChildren<Camera>(true);
			for (int j = 0; j < componentsInChildren5.Length; j++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren5[j]);
			}
			AudioListener[] componentsInChildren6 = clone.GetComponentsInChildren<AudioListener>(true);
			for (int j = 0; j < componentsInChildren6.Length; j++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren6[j]);
			}
			Light[] componentsInChildren7 = clone.GetComponentsInChildren<Light>(true);
			foreach (Light val in componentsInChildren7)
			{
				if ((Object)(object)val != (Object)(object)keepLight)
				{
					Object.DestroyImmediate((Object)(object)val);
				}
			}
			AudioSource[] componentsInChildren8 = clone.GetComponentsInChildren<AudioSource>(true);
			for (int j = 0; j < componentsInChildren8.Length; j++)
			{
				((Behaviour)componentsInChildren8[j]).enabled = false;
			}
		}

		private void AddHeadLight()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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)
			GameObject val = new GameObject("GruffyHeadLight");
			val.transform.SetParent(HeadPoint, false);
			val.transform.localPosition = new Vector3(0f, 0.1f, 0.15f);
			Light obj = val.AddComponent<Light>();
			obj.type = (LightType)2;
			obj.range = 3.5f;
			obj.intensity = 0.6f;
			obj.color = new Color(1f, 0.85f, 0.6f);
			obj.shadows = (LightShadows)0;
		}

		internal void Drive(Vector3 groundPosition, float targetYaw, Vector3 velocity, bool sprinting, bool crouching, bool grabbing, Vector3? lookTarget = null, Vector3? grabPoint = null)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: 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_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: 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_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: 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_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: 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_02d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04aa: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Visual == (Object)null)
			{
				return;
			}
			LastPosition = groundPosition;
			LastTargetYaw = targetYaw;
			LastVelocity = velocity;
			LastSprinting = sprinting;
			LastCrouching = crouching;
			LastGrabbing = grabbing;
			LastLook = lookTarget;
			LastGrabPoint = grabPoint;
			float deltaTime = Time.deltaTime;
			Vector3 val = new Vector3(velocity.x, 0f, velocity.z);
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (animParams.Count == 0 && ((Behaviour)animator).isActiveAndEnabled)
			{
				AnimatorControllerParameter[] parameters = animator.parameters;
				foreach (AnimatorControllerParameter val2 in parameters)
				{
					animParams.Add(val2.name);
				}
				Plugin.Debug("Animator parameters: " + string.Join(", ", animParams));
			}
			float y = groundPosition.y;
			RaycastHit val3 = default(RaycastHit);
			if (Physics.Raycast(groundPosition + Vector3.up * 0.35f, Vector3.down, ref val3, 1.35f, LayerMask.GetMask(new string[1] { "Default" }), (QueryTriggerInteraction)1))
			{
				y = ((RaycastHit)(ref val3)).point.y;
			}
			float num = y + footOffset;
			visualY = (visualYInitialized ? Mathf.Lerp(visualY, num, 1f - Mathf.Exp(-15f * deltaTime)) : num);
			visualYInitialized = true;
			Visual.position = new Vector3(groundPosition.x, visualY, groundPosition.z);
			Quaternion val4 = rig.BodyRotation(Quaternion.Euler(0f, yaw, 0f), Quaternion.Euler(0f, targetYaw, 0f), deltaTime);
			yaw = ((Quaternion)(ref val4)).eulerAngles.y;
			bool flag = magnitude > 0.15f;
			bool flag2 = tumbleTimer > 0f;
			if (flag2)
			{
				tumbleTimer -= deltaTime;
				if (flag)
				{
					rollAngle += magnitude / 0.45f * 57.29578f * deltaTime;
				}
			}
			else if (Mathf.Abs(Mathf.DeltaAngle(rollAngle, 0f)) > 0.5f)
			{
				rollAngle = Mathf.MoveTowardsAngle(rollAngle, 0f, 540f * deltaTime);
			}
			else
			{
				rollAngle = 0f;
			}
			Quaternion val5 = Quaternion.Euler(rollAngle, 0f, 0f);
			Visual.rotation = val4 * val5;
			if (rollAngle != 0f)
			{
				Vector3 val6 = Visual.position + Vector3.up * 0.45f;
				Visual.position = val6 - Visual.rotation * (Vector3.up * 0.45f);
			}
			float num2 = Mathf.Abs(Mathf.DeltaAngle(previousYaw, yaw));
			previousYaw = yaw;
			if (num2 > 0.5f)
			{
				turningTimer = 0.2f;
			}
			else
			{
				turningTimer -= deltaTime;
			}
			float num3 = Mathf.DeltaAngle(previousTargetYaw, targetYaw);
			if (Mathf.Abs(num3) > 0.01f)
			{
				turnDifference = Mathf.Abs(num3);
				turnDirection = 0f - Mathf.Sign(num3);
			}
			else
			{
				turnDifference = Mathf.MoveTowards(turnDifference, 0f, deltaTime * 20f);
			}
			previousTargetYaw = targetYaw;
			bool flag3 = sprinting && flag && !crouching && !flag2;
			if (flag3 && !sprintingPrevious)
			{
				SetTrigger("SprintingImpulse");
			}
			sprintingPrevious = flag3;
			SetBool("Moving", flag);
			SetBool("Sprinting", flag3);
			SetBool("Turning", !flag && !flag2 && turningTimer > 0f);
			SetBool("Crouching", crouching || flag2 || Crawl);
			SetBool("Crawling", flag2 || Crawl);
			SetBool("Sliding", value: false);
			SetBool("Jumping", value: false);
			SetBool("Falling", value: false);
			SetBool("Tumbling", flag2);
			SetBool("TumblingMove", flag2 && flag);
			SetBool("Grabbing", grabbing);
			animator.speed = 1f;
			rig.Tick(Visual, velocity, flag, flag3, crouching, grabbing, lookTarget, grabPoint, turnDifference, turnDirection, deltaTime);
		}

		internal void StartTumble(float duration)
		{
			if (tumbleTimer <= 0f)
			{
				SetTrigger("TumblingImpulse");
			}
			tumbleTimer = Mathf.Max(tumbleTimer, duration);
			Tumbled?.Invoke(duration);
		}

		internal void SetVisible(bool visible)
		{
			if ((Object)(object)Visual != (Object)null && ((Component)Visual).gameObject.activeSelf != visible)
			{
				((Component)Visual).gameObject.SetActive(visible);
				visualYInitialized = false;
			}
		}

		internal void SetMouthLoudness(float loudness)
		{
			mouthLoudness = loudness;
		}

		private void LateUpdate()
		{
			//IL_004b: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)jaw == (Object)null))
			{
				float num = ((mouthLoudness > 0.005f) ? Mathf.Lerp(0f, -45f, mouthLoudness * 4f) : 0f);
				jaw.localRotation = Quaternion.Slerp(jaw.localRotation, Quaternion.Euler(num, 0f, 0f), 1f - Mathf.Exp(-40f * Time.deltaTime));
			}
		}

		private void SetBool(string name, bool value)
		{
			if (animParams.Contains(name))
			{
				animator.SetBool(name, value);
			}
		}

		private void SetTrigger(string name)
		{
			if (animParams.Contains(name))
			{
				animator.SetTrigger(name);
			}
		}
	}
	internal class GruffyAnimationEvents : MonoBehaviour
	{
		private readonly MaterialTrigger materialTrigger = new MaterialTrigger();

		private float lastStep;

		public void FootstepLight()
		{
			Step((SoundType)0);
		}

		public void FootstepMedium()
		{
			Step((SoundType)1);
		}

		public void FootstepHeavy()
		{
			Step((SoundType)2);
		}

		public void StandToCrouch()
		{
		}

		public void CrouchToStand()
		{
		}

		public void CrouchToCrawl()
		{
		}

		public void CrawlToCrouch()
		{
		}

		public void RightFootUp()
		{
		}

		public void RightFootUpSlow()
		{
		}

		public void RightFootDown()
		{
		}

		public void RightFootDownSlow()
		{
		}

		public void LeftFootUp()
		{
		}

		public void LeftFootUpSlow()
		{
		}

		public void LeftFootDown()
		{
		}

		public void LeftFootDownSlow()
		{
		}

		private void Step(SoundType type)
		{
			//IL_0032: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_0051: 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_0057: 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_007c: Invalid comparison between Unknown and I4
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Invalid comparison between Unknown and I4
			//IL_0083: 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_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_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time - lastStep < 0.12f || (Object)(object)Materials.Instance == (Object)null)
			{
				return;
			}
			lastStep = Time.time;
			try
			{
				Vector3 val = ((Component)this).transform.position + Vector3.up * 0.1f;
				Materials.Instance.Impulse(val, Vector3.down, type, true, true, materialTrigger, (HostType)1);
				if ((Object)(object)EnemyDirector.instance != (Object)null && SemiFunc.IsMasterClientOrSingleplayer())
				{
					if ((int)type == 2)
					{
						EnemyDirector.instance.SetInvestigate(val + Vector3.up * 0.2f, 5f, false);
					}
					else if ((int)type == 1)
					{
						EnemyDirector.instance.SetInvestigate(val + Vector3.up * 0.2f, 1f, false);
					}
				}
			}
			catch
			{
			}
		}
	}
	internal class GruffyBrain : MonoBehaviour
	{
		private enum State
		{
			Follow,
			Seek,
			Carry,
			Flee,
			Cower,
			Hide,
			OpenContainer,
			Scout,
			Tow,
			PressConfirm,
			SmashGnome
		}

		private enum Delivery
		{
			CartOrPlayer,
			Extraction,
			Truck,
			HoldInZone,
			HeroCart
		}

		private class MonsterKind
		{
			internal EnemyDuck Duck;

			internal EnemyTricycle Bella;

			internal EnemyElsa Elsa;

			internal EnemyBirthdayBoy BirthdayBoy;

			internal EnemyHeartHugger HeartHugger;

			internal EnemyGnome Gnome;
		}

		private PhysGrabCart towTarget;

		private PhysGrabCart towSkipCart;

		private float towSkipUntil;

		private int towRehooks;

		private Vector3 towExit;

		private bool towExitLocked;

		private float towSettleTimer;

		private float towStartedAt;

		private float towWaitTimer;

		private State state;

		private float stateTimer;

		private GruffyBody body;

		private GruffyVoice voice;

		private GruffyCarrier carrier;

		private GruffyNavigator nav;

		private bool initialized;

		private int health;

		private bool dead;

		private GruffyHead head;

		private float contactDamageCooldown;

		private float truckReviveTimer;

		private readonly Collider[] overlapBuffer = (Collider[])(object)new Collider[16];

		private readonly RaycastHit[] rayBuffer = (RaycastHit[])(object)new RaycastHit[16];

		private PhysGrabHinge lastHinge;

		private int hingeAttempts;

		private float hingeWaitTimer;

		private float unreachableTimer;

		private float braveTimer;

		private float panicTime;

		private string lastHeroStatus;

		private float idleTimer = 2f;

		private float lookAroundTimer = 3f;

		private float lookYaw;

		private PhysGrabObject seekGrab;

		private ValuableObject seekValuable;

		private Delivery delivery;

		private float scanTimer = 3f;

		private readonly Dictionary<int, float> blacklist = new Dictionary<int, float>();

		private float releaseHoldTimer;

		private bool fragileLineSaid;

		private float lostGripTimer;

		private PhysGrabCart cart;

		private float cartRefreshTimer;

		private ExtractionPoint heroExtraction;

		private Component confirmButton;

		private float confirmCooldown;

		private bool rescueLineSaid;

		private bool heroNothingKnown;

		private float threatScanTimer;

		private bool threatActive;

		private Vector3 threatPosition;

		private float threatClearTimer;

		private float nearestEnemyDistance = float.MaxValue;

		private bool playerThreatened;

		private bool sensedHauntedEnemy;

		private Vector3 fleeGoal;

		private float greetTimer = 1.2f;

		private float idleChatterAt;

		private int lastExtractions;

		private bool missionDone;

		private bool playerWasDead;

		private bool gruffyCarrying;

		private bool leaving;

		private float leaveTimer;

		private float errorLogCooldown;

		private int colorIndex = -1;

		private readonly List<PlayerDeathHead> deadHeads = new List<PlayerDeathHead>();

		private float lastSpottedTime = -100f;

		private Vector3 lastSpottedAt;

		private bool beingHunted;

		private string threatName;

		private float hideSearchTimer;

		private float hideRetryAt;

		private float tuckTimer;

		private float diveTimer;

		private float invulnerableUntil;

		private PhysGrabHinge hideDoor;

		private float doorWait;

		private readonly Collider[] hingeBuffer = (Collider[])(object)new Collider[64];

		private readonly HashSet<PhysGrabHinge> hingesTried = new HashSet<PhysGrabHinge>();

		private EnemyGnome gnomeTarget;

		private int gnomePhase;

		private float gnomeTimer;

		private int gnomeSlams;

		private float gnomeScanTimer;

		private readonly Dictionary<EnemyGnome, float> gnomeSkipUntil = new Dictionary<EnemyGnome, float>();

		private const float GnomeRange = 12f;

		private PhysGrabCart heroCart;

		private float heroCartTimer;

		private readonly List<PhysGrabCart> allCarts = new List<PhysGrabCart>();

		private float cartListTimer;

		private float truckPhaseTimer;

		private float truckWaitTimer;

		private bool levelEndSent;

		private readonly Dictionary<Enemy, MonsterKind> monsterKinds = new Dictionary<Enemy, MonsterKind>();

		private readonly Dictionary<Enemy, bool> lastCalm = new Dictionary<Enemy, bool>();

		private LevelPoint scoutPoint;

		private readonly Dictionary<int, float> searchedRooms = new Dictionary<int, float>();

		private float scoutCooldown = 3f;

		private bool scoutLooking;

		private float scoutLookTimer;

		private float scoutLookStartYaw;

		private float scoutLookYaw;

		private const float LookAroundTime = 2.5f;

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

		private float perceptionTimer;

		private int perceptionCursor;

		private const float SightRange = 16f;

		private const float SightHalfAngle = 75f;

		private float noticeCooldown;

		private float hurtScanTimer;

		private float hurtCooldown;

		private Vector3 knockVelocity;

		private float knockTimer;

		private int lastPlayerHealth = -1;

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

		private PhysGrabHinge searchHinge;

		private float curiosityTimer = 12f;

		private readonly List<Enemy> huntKeys = new List<Enemy>();

		private readonly Dictionary<Enemy, float> huntedBy = new Dictionary<Enemy, float>();

		private readonly Dictionary<Enemy, float> enemyAttackCooldown = new Dictionary<Enemy, float>();

		private readonly Dictionary<Enemy, int> enemyDamageCache = new Dictionary<Enemy, int>();

		private float attackScanTimer;

		private Vector3? hideTuck;

		private bool hideLow;

		private bool tucking;

		private bool goingToHide;

		private float hideClearTimer;

		private float lastHurtTime = -100f;

		private float spawnTime;

		private const float SpawnGrace = 5f;

		internal bool IsLeaving => leaving;

		internal bool Initialized => initialized;

		internal GruffyBody Body => body;

		internal int ColorIndex => colorIndex;

		internal int HeadViewId
		{
			get
			{
				if (head == null || !head.Exists)
				{
					return 0;
				}
				return head.ViewId;
			}
		}

		internal Vector3 HeadPosition
		{
			get
			{
				//IL_001b: 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 (head == null || !head.Exists)
				{
					return ((Component)this).transform.position;
				}
				return head.Position;
			}
		}

		internal bool IsAlive
		{
			get
			{
				if (initialized && !dead)
				{
					return !leaving;
				}
				return false;
			}
		}

		internal Transform SpectateTarget
		{
			get
			{
				if (!((Object)(object)body != (Object)null) || !((Object)(object)body.HeadPoint != (Object)null))
				{
					return ((Component)this).transform;
				}
				return body.HeadPoint;
			}
		}

		private static bool LastStanding => GruffyManager.GruffyIsLastStanding();

		private static int HideMask => LayerMask.GetMask(new string[3] { "Default", "StaticGrabObject", "PhysGrabObjectHinge" });

		private string ThreatLabel
		{
			get
			{
				if (!string.IsNullOrEmpty(threatName))
				{
					return "the " + threatName;
				}
				return "a monster";
			}
		}

		private void GiveUpOnCart(string why)
		{
			HeroStatus("gave up on the cart for now: " + why);
			towSkipCart = towTarget;
			towSkipUntil = Time.time + 60f;
			carrier.StopTow();
			SetState(State.Follow);
		}

		private static bool CartHasLoot(PhysGrabCart target)
		{
			//IL_003f: 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)
			//IL_0054: 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 ((Object)(object)target == (Object)null)
			{
				return false;
			}
			if ((Object)(object)target.inCart == (Object)null)
			{
				if (target.itemsInCartCount <= 0)
				{
					return target.haulCurrent > 0;
				}
				return true;
			}
			int num = LayerMask.NameToLayer("PhysGrabObject");
			Collider[] array = Physics.OverlapBox(target.inCart.position, target.inCart.localScale / 2f, target.inCart.rotation);
			foreach (Collider val in array)
			{
				if (((Component)val).gameObject.layer == num && (Object)(object)((Component)val).GetComponentInParent<ValuableObject>() != (Object)null)
				{
					return true;
				}
				PlayerDeathHead componentInParent = ((Component)val).GetComponentInParent<PlayerDeathHead>();
				if ((Object)(object)componentInParent != (Object)null && componentInParent.triggered)
				{
					return true;
				}
			}
			return false;
		}

		private static bool CartInExtraction(PhysGrabCart target)
		{
			RoomVolumeCheck val = (((Object)(object)target != (Object)null && (Object)(object)target.physGrabObject != (Object)null) ? target.physGrabObject.roomVolumeCheck : null);
			if ((Object)(object)val != (Object)null)
			{
				return val.inExtractionPoint;
			}
			return false;
		}

		private PhysGrabCart FindLootCart()
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			PhysGrabCart result = null;
			float num = float.MaxValue;
			PhysGrabCart[] array = Object.FindObjectsOfType<PhysGrabCart>();
			foreach (PhysGrabCart val in array)
			{
				if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeInHierarchy && CartHasLoot(val) && !CartInExtraction(val) && (!((Object)(object)val.physGrabObject != (Object)null) || val.physGrabObject.playerGrabbing.Count <= 0) && (!((Object)(object)val == (Object)(object)towSkipCart) || !(Time.time < towSkipUntil)))
				{
					float num2 = Vector3.Distance(((Component)val).transform.position, nav.Position);
					if (num2 < num)
					{
						num = num2;
						result = val;
					}
				}
			}
			return result;
		}

		private void StartTow(PhysGrabCart target)
		{
			towTarget = target;
			towRehooks = 0;
			towStartedAt = Time.time;
			towWaitTimer = 0f;
			SetState(State.Tow);
		}

		private void UpdateTow(ref float speed, ref bool sprinting)
		{
			//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)
			//IL_00bf: 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_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: 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_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: 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_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: 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)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d5: 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_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0393: Unknown result type (might be due to invalid IL or missing references)
			//IL_039e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a3: 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)
			if ((Object)(object)towTarget == (Object)null || !((Component)towTarget).gameObject.activeInHierarchy || !LastStanding || (Object)(object)heroExtraction == (Object)null)
			{
				carrier.StopTow();
				SetState(State.Follow);
				return;
			}
			Vector3 val = ExtractionCenter(heroExtraction);
			if (Time.time - towStartedAt > 150f)
			{
				GiveUpOnCart("took too long");
				return;
			}
			Vector3 val3;
			if ((Object)(object)carrier.TowCart != (Object)(object)towTarget)
			{
				Vector3 val2 = (((Object)(object)towTarget.handlePoint != (Object)null) ? towTarget.handlePoint.position : ((Component)towTarget).transform.position);
				HeroStatus("going back for the cart");
				GoTo(val2, 2.5f);
				val3 = NoY(val2 - nav.Position);
				sprinting = ((Vector3)(ref val3)).magnitude > 6f;
				if (Vector3.Distance(nav.Position + Vector3.up * 1f, val2) < 2.6f)
				{
					if (towRehooks >= 5)
					{
						GiveUpOnCart("it keeps getting stuck");
						return;
					}
					towRehooks++;
					carrier.BeginTow(towTarget);
					stateTimer = 0f;
				}
				else if (stateTimer > 45f)
				{
					GiveUpOnCart("couldn't reach it");
				}
				return;
			}
			HeroStatus("towing the cart to the extraction point");
			speed = Plugin.WalkSpeed.Value * 0.75f;
			sprinting = false;
			if (carrier.UnstickAttempts >= 5)
			{
				HeroStatus("cart is stuck; re-hooking it from another angle");
				carrier.StopTow();
				return;
			}
			if (carrier.TrailGap > 4.5f)
			{
				speed = 0f;
				towWaitTimer += Time.deltaTime;
				if (carrier.TrailGap > 8f || towWaitTimer > 2f)
				{
					HeroStatus($"cart is snagged {carrier.TrailGap:0.0}m back; going back to re-hook it");
					towWaitTimer = 0f;
					carrier.StopTow();
				}
				return;
			}
			towWaitTimer = 0f;
			val3 = NoY(((Component)towTarget).transform.position - val);
			float magnitude = ((Vector3)(ref val3)).magnitude;
			if (!towExitLocked || magnitude > 6f)
			{
				Vector3 val4 = NoY(val - ((Component)towTarget).transform.position);
				towExit = val + ((((Vector3)(ref val4)).sqrMagnitude > 0.01f) ? ((Vector3)(ref val4)).normalized : body.Forward) * 2f;
				towExitLocked = magnitude < 4f;
			}
			GoTo(towExit, 3f);
			if (CartInExtraction(towTarget) && magnitude < 0.9f)
			{
				towSettleTimer += Time.deltaTime;
				speed = 0f;
				if (towSettleTimer > 0.4f)
				{
					HeroStatus("cart is parked in the extraction point");
					carrier.StopTow(brake: true);
					voice.Say(SpeechType.CartDrop, 1f, 10f);
					towExitLocked = false;
					towSettleTimer = 0f;
					SetState(State.Follow);
				}
			}
			else
			{
				towSettleTimer = 0f;
				val3 = NoY(towExit - nav.Position);
				if (((Vector3)(ref val3)).magnitude < 0.8f && !CartInExtraction(towTarget))
				{
					towExitLocked = false;
				}
				if (stateTimer > 90f)
				{
					GiveUpOnCart("took too long");
				}
			}
		}

		internal bool Initialize(PlayerAvatar player, out string error)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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_0044: 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_007e: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: 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)
			//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_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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)
			error = null;
			Vector3 position = ((Component)player).transform.position;
			nav = new GruffyNavigator(position);
			Vector3 val = NoY(((Component)player).transform.forward);
			Vector3 point = position - ((Vector3)(ref val)).normalized * 3f;
			if (!nav.Sample(point, 2.5f, out var result) && !nav.Sample(position, 4f, out result))
			{
				error = "no navmesh near the player to stand on";
				return false;
			}
			nav.Warp(result);
			((Component)this).transform.position = result;
			Vector3 val2 = NoY(position - result);
			((Component)this).transform.rotation = ((((Vector3)(ref val2)).sqrMagnitude > 0.01f) ? Quaternion.LookRotation(val2) : Quaternion.identity);
			lookYaw = ((Component)this).transform.eulerAngles.y;
			body = ((Component)this).gameObject.AddComponent<GruffyBody>();
			if (!body.Build(player, PickColor(), out error))
			{
				return false;
			}
			voice = ((Component)this).gameObject.AddComponent<GruffyVoice>();
			voice.Build(body.HeadPoint);
			voice.Spoke = GruffyNet.SendSay;
			body.Tumbled = GruffyNet.SendTumble;
			carrier = ((Component)this).gameObject.AddComponent<GruffyCarrier>();
			carrier.Build(player);
			carrier.BeamOrigin = body.HandPoint;
			health = Plugin.GruffyMaxHealth.Value;
			if ((Object)(object)RoundDirector.instance != (Object)null)
			{
				lastExtractions = RoundDirector.instance.extractionPointsCompleted;
				missionDone = RoundDirector.instance.allExtractionPointsCompleted;
			}
			ScheduleIdleChatter();
			spawnTime = Time.time;
			initialized = true;
			return true;
		}

		private Color? PickColor()
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				List<SemiColor> list = (((Object)(object)MetaManager.instance != (Object)null) ? MetaManager.instance.colors : null);
				if (list == null || list.Count == 0)
				{
					return null;
				}
				int num = Plugin.ColorIndex.Value;
				if (num < 0 || num >= list.Count)
				{
					num = Random.Range(0, list.Count);
				}
				colorIndex = num;
				return list[num].color;
			}
			catch
			{
				return null;
			}
		}

		internal void Leave()
		{
			if (!leaving)
			{
				leaving = true;
				leaveTimer = (dead ? 0f : 6f);
				carrier.Release(stopObject: false);
				nav.Stop();
				if (!dead)
				{
					voice.Say(SpeechType.Goodbye, 1f, 20f, force: true);
				}
			}
		}

		private void OnDestroy()
		{
			head?.Destroy();
			head = null;
			GruffyNet.SendGone();
		}

		private void Update()
		{
			if (!initialized)
			{
				return;
			}
			try
			{
				Tick();
			}
			catch (Exception ex)
			{
				errorLogCooldown -= Time.deltaTime;
				if (errorLogCooldown <= 0f)
				{
					errorLogCooldown = 5f;
					Plugin.Log.LogError((object)("Gruffy brain error: " + ex));
				}
			}
		}

		private void Tick()
		{
			//IL_004f: 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_010a: 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_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: 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_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_0302: Unknown result type (might be due to invalid IL or missing references)
			//IL_0447: Unknown result type (might be due to invalid IL or missing references)
			//IL_046b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0470: Unknown result type (might be due to invalid IL or missing references)
			//IL_0475: Unknown result type (might be due to invalid IL or missing references)
			//IL_0481: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_05aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_05af: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_05de: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_054c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0557: Unknown result type (might be due to invalid IL or missing references)
			//IL_055c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0561: Unknown result type (might be due to invalid IL or missing references)
			//IL_0566: Unknown result type (might be due to invalid IL or missing references)
			//IL_07bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_07d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_07df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0628: Unknown result type (might be due to invalid IL or missing references)
			//IL_062f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0634: Unknown result type (might be due to invalid IL or missing references)
			//IL_0639: Unknown result type (might be due to invalid IL or missing references)
			//IL_063e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0605: Unknown result type (might be due to invalid IL or missing references)
			//IL_0607: Unknown result type (might be due to invalid IL or missing references)
			//IL_060c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0610: Unknown result type (might be due to invalid IL or missing references)
			//IL_0583: Unknown result type (might be due to invalid IL or missing references)
			//IL_0585: Unknown result type (might be due to invalid IL or missing references)
			//IL_058a: Unknown result type (might be due to invalid IL or missing references)
			//IL_058e: Unknown result type (might be due to invalid IL or missing references)
			//IL_065b: Unknown result type (might be due to invalid IL or missing references)
			//IL_065d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0662: Unknown result type (might be due to invalid IL or missing references)
			//IL_0666: Unknown result type (might be due to invalid IL or missing references)
			//IL_077f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0740: Unknown result type (might be due to invalid IL or missing references)
			float deltaTime = Time.deltaTime;
			PlayerAvatar instance = PlayerAvatar.instance;
			body.SetMouthLoudness(voice.Loudness);
			if (leaving)
			{
				leaveTimer -= deltaTime;
				if (!dead)
				{
					body.Drive(nav.Position, body.Yaw, Vector3.zero, sprinting: false, crouching: false, grabbing: false, PlayerLookPoint());
				}
				if (leaveTimer <= 0f || (leaveTimer < 4.5f && !voice.IsSpeaking))
				{
					Object.Destroy((Object)(object)((Component)this).gameObject);
				}
				return;
			}
			if (dead)
			{
				TickDead();
				return;
			}
			if ((Object)(object)instance == (Object)null)
			{
				body.Drive(nav.Position, body.Yaw, Vector3.zero, sprinting: false, crouching: false, grabbing: false);
				return;
			}
			Vector3 position = ((Component)instance).transform.position;
			stateTimer += deltaTime;
			contactDamageCooldown -= deltaTime;
			confirmCooldown -= deltaTime;
			ScanThreats(position, deltaTime);
			SensesTick(deltaTime);
			if (dead)
			{
				return;
			}
			Commentary(instance);
			braveTimer -= deltaTime;
			diveTimer -= deltaTime;
			if ((state == State.Flee || state == State.Cower) && !beingHunted && !goingToHide)
			{
				panicTime += deltaTime;
				if (panicTime > (LastStanding ? 5f : 10f))
				{
					panicTime = 0f;
					braveTimer = 10f;
					threatActive = false;
					SetState(State.Follow);
					if (LastStanding)
					{
						HeroStatus("got brave; back to work");
					}
				}
			}
			else
			{
				panicTime = Mathf.Max(0f, panicTime - deltaTime);
			}
			if (Plugin.FleeFromEnemies.Value && threatActive && state != State.Flee && state != State.Cower && state != State.Hide)
			{
				if (LastStanding)
				{
					HeroStatus($"running from a monster {nearestEnemyDistance:0}m away");
				}
				EnterFlee();
			}
			if (state == State.Follow || state == State.Scout || state == State.Seek || state == State.OpenContainer)
			{
				TryStartGnomeHunt();
			}
			float speed = Plugin.WalkSpeed.Value;
			bool sprinting = false;
			bool crouching = false;
			bool lookAtPlayer = false;
			float stopDistance = 0.4f;
			switch (state)
			{
			case State.Follow:
				if (LastStanding)
				{
					UpdateHero(ref sprinting);
				}
				else
				{
					UpdateFollow(instance, position, ref sprinting, ref crouching, ref lookAtPlayer);
				}
				break;
			case State.Seek:
				UpdateSeek(position, ref sprinting);
				stopDistance = 1.2f;
				break;
			case State.Carry:
				UpdateCarry(position, ref speed, ref sprinting);
				stopDistance = 0.8f;
				break;
			case State.Flee:
				UpdateFlee(ref sprinting);
				stopDistance = (tucking ? 0.05f : 0.8f);
				break;
			case State.Scout:
				UpdateScout(position, ref sprinting);
				stopDistance = 0.8f;
				break;
			case State.SmashGnome:
				UpdateSmashGnome(ref sprinting);
				stopDistance = 2f;
				break;
			case State.Cower:
				UpdateCower(ref crouching);
				break;
			case State.Hide:
				UpdateHide(ref crouching);
				break;
			case State.OpenContainer:
				UpdateOpenContainer(ref sprinting);
				stopDistance = 0.8f;
				break;
			case State.Tow:
				UpdateTow(ref speed, ref sprinting);
				stopDistance = 0.6f;
				break;
			case State.PressConfirm:
				UpdatePressConfirm(ref sprinting);
				stopDistance = 0.8f;
				break;
			}
			if (crouching)
			{
				speed *= 0.5f;
				sprinting = false;
			}
			if (body.IsTumbling && diveTimer <= 0f)
			{
				speed *= 0.6f;
				sprinting = false;
			}
			ApplyKnockback(deltaTime);
			float speed2 = speed;
			if (sprinting)
			{
				speed2 = Plugin.SprintSpeed.Value * ((state == State.Flee && beingHunted) ? 1.15f : 1f);
			}
			nav.Tick(speed2, stopDistance);
			CatchUpIfLost(instance, position);
			if (state != State.Flee && state != State.Cower)
			{
				HandleUnreachable();
			}
			Vector3 val = NoY(nav.Velocity);
			float magnitude = ((Vector3)(ref val)).magnitude;
			ShoveDoorsInTheWay(val);
			Vector3? beamPoint = carrier.BeamPoint;
			Vector3? lookTarget = null;
			Quaternion val3;
			float num2;
			if (carrier.IsPullingHinge && beamPoint.HasValue)
			{
				Vector3 val2 = NoY(beamPoint.Value - nav.Position);
				float num;
				if (!(((Vector3)(ref val2)).sqrMagnitude > 0.01f))
				{
					num = body.Yaw;
				}
				else
				{
					val3 = Quaternion.LookRotation(val2);
					num = ((Quaternion)(ref val3)).eulerAngles.y;
				}
				num2 = num;
				lookTarget = beamPoint;
			}
			else if (state == State.Scout && scoutLooking)
			{
				num2 = scoutLookYaw;
			}
			else if (state == State.SmashGnome && carrier.IsYanking && beamPoint.HasValue)
			{
				Vector3 val4 = NoY(beamPoint.Value - nav.Position);
				float num3;
				if (!(((Vector3)(ref val4)).sqrMagnitude > 0.01f))
				{
					num3 = body.Yaw;
				}
				else
				{
					val3 = Quaternion.LookRotation(val4);
					num3 = ((Quaternion)(ref val3)).eulerAngles.y;
				}
				num2 = num3;
			}
			else if (magnitude > 0.1f)
			{
				val3 = Quaternion.LookRotation(val);
				num2 = ((Quaternion)(ref val3)).eulerAngles.y;
			}
			else if (state == State.Cower)
			{
				Vector3 val5 = NoY(nav.Position - threatPosition);
				float num4;
				if (!(((Vector3)(ref val5)).sqrMagnitude > 0.01f))
				{
					num4 = body.Yaw;
				}
				else
				{
					val3 = Quaternion.LookRotation(val5);
					num4 = ((Quaternion)(ref val3)).eulerAngles.y;
				}
				num2 = num4;
			}
			else if (lookAtPlayer)
			{
				Vector3 val6 = NoY(position - nav.Position);
				float num5;
				if (!(((Vector3)(ref val6)).sqrMagnitude > 0.01f))
				{
					num5 = body.Yaw;
				}
				else
				{
					val3 = Quaternion.LookRotation(val6);
					num5 = ((Quaternion)(ref val3)).eulerAngles.y;
				}
				num2 = num5;
				lookAroundTimer -= deltaTime;
				if (lookAroundTimer <= 0f)
				{
					lookAroundTimer = Random.Range(3f, 7f);
					lookYaw = num2 + Random.Range(-100f, 100f);
				}
				if (lookAroundTimer > 1.8f && lookAroundTimer < 3f)
				{
					num2 = lookYaw;
				}
			}
			else
			{
				num2 = body.Yaw;
			}
			if (!lookTarget.HasValue)
			{
				if (beamPoint.HasValue)
				{
					lookTarget = beamPoint;
				}
				else if (state == State.Seek && (Object)(object)seekGrab != (Object)null && (Object)(object)seekGrab.rb != (Object)null)
				{
					lookTarget = seekGrab.rb.worldCenterOfMass;
				}
				else if (((state == State.Flee || state == State.Cower) && threatActive) || (state == State.Hide && nearestEnemyDistance < 14f))
				{
					lookTarget = threatPosition;
				}
				else if (lookAtPlayer && (!(lookAroundTimer > 1.8f) || !(lookAroundTimer < 3f)))
				{
					lookTarget = PlayerLookPoint();
				}
			}
			((Component)this).transform.position = nav.Position;
			body.Drive(nav.Position, num2, nav.Velocity, sprinting, crouching, carrier.IsBeamActive, lookTarget, beamPoint);
		}

		private static Vector3? PlayerLookPoint()
		{
			//IL_006c: 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_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)
			PlayerAvatar instance = PlayerAvatar.instance;
			if ((Object)(object)instance == (Object)null || instance.isDisabled)
			{
				return null;
			}
			Camera val = (((Object)(object)GameDirector.instance != (Object)null) ? GameDirector.instance.MainCamera : null);
			return ((Object)(object)val != (Object)null) ? ((Component)val).transform.position : (((Component)instance).transform.position + Vector3.up * 1.5f);
		}

		private void ShoveDoorsInTheWay(Vector3 velocity)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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_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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
			if (((Vector3)(ref velocity)).sqrMagnitude < 0.04f)
			{
				return;
			}
			Vector3 normalized = ((Vector3)(ref velocity)).normalized;
			Vector3 val = nav.Position + Vector3.up * 1f + normalized * 0.6f;
			int num = Physics.OverlapSphereNonAlloc(val, 0.55f, overlapBuffer, LayerMask.GetMask(new string[1] { "PhysGrabObjectHinge" }), (QueryTriggerInteraction)1);
			for (int i = 0; i < num; i++)
			{
				PhysGrabHinge componentInParent = ((Component)overlapBuffer[i]).GetComponentInParent<PhysGrabHinge>();
				if (!((Object)(object)componentInParent == (Object)null) && !componentInParent.dead && !componentInParent.broken)
				{
					Rigidbody component = ((Component)componentInParent).GetComponent<Rigidbody>();
					Vector3 point = overlapBuffer[i].ClosestPoint(val);
					GruffyCarrier.ShoveHinge(component, point, normalized);
				}
			}
		}

		private void UpdateFollow(PlayerAvatar player, Vector3 playerPos, ref bool sprinting, ref bool crouching, ref bool lookAtPlayer)
		{
			//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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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_0071: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: 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_00af: 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_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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_00cf: 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_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: 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_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			float value = Plugin.FollowMinDistance.Value;
			float num = Mathf.Max(Plugin.FollowMaxDistance.Value, value + 1f);
			Vector3 position = nav.Position;
			Vector3 val = NoY(playerPos - position);
			float magnitude = ((Vector3)(ref val)).magnitude;
			crouching = !player.isDisabled && (player.isCrouching || player.isCrawling) && magnitude < 6f;
			if (magnitude > num)
			{
				Vector3 val2 = NoY(position - playerPos);
				Vector3 val3;
				if (!(((Vector3)(ref val2)).sqrMagnitude > 0.01f))
				{
					val = NoY(((Component)player).transform.forward);
					val3 = -((Vector3)(ref val)).normalized;
				}
				else
				{
					val3 = ((Vector3)(ref val2)).normalized;
				}
				val2 = val3;
				Vector3 target = playerPos + val2 * Mathf.Lerp(value, num, 0.35f);
				nav.SetDestination(target);
				sprinting = magnitude > num * 1.8f || player.isSprinting;
				idleTimer = Random.Range(2f, 5f);
			}
			else if (magnitude < value * 0.55f)
			{
				Vector3 val4 = NoY(position - playerPos);
				Vector3 normalized;
				if (!(((Vector3)(ref val4)).sqrMagnitude > 0.01f))
				{
					val = NoY(Random.insideUnitSphere);
					normalized = ((Vector3)(ref val)).normalized;
				}
				else
				{
					normalized = ((Vector3)(ref val4)).normalized;
				}
				val4 = normalized;
				nav.SetDestination(position + val4 * (value * 0.7f));
			}
			else if (!nav.HasPath)
			{
				lookAtPlayer = true;
				if ((SemiFunc.RunIsLevel() && Plugin.CollectValuables.Value && TryStartSearch()) || (SemiFunc.RunIsLevel() && Plugin.CollectValuables.Value && Plugin.Scouting.Value && !playerThreatened && !threatActive && ScoutDue() && TryStartScout(playerPos, Plugin.ScoutRadius.Value)))
				{
					return;
				}
				Wander(playerPos, value, num);
			}
			if (!Plugin.CollectValuables.Value || !SemiFunc.RunIsLevel() || player.isDisabled)
			{
				return;
			}
			scanTimer -= Time.deltaTime;
			if (scanTimer <= 0f)
			{
				scanTimer = 1f;
				ValuableObject val5 = FindValuable(playerPos, CollectRange(), Plugin.CollectSizes.Value);
				if ((Object)(object)val5 != (Object)null)
				{
					StartFetch(val5.physGrabObject, val5, Delivery.CartOrPlayer);
					voice.Say(SpeechType.ItemSpotted, 0.3f, 15f);
				}
			}
		}

		private void Wander(Vector3 around, float min, float max)
		{
			//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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: 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_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_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: 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_00ee: Unknown result type (might be due to invalid IL or missing references)
			idleTimer -= Time.deltaTime;
			if (idleTimer > 0f)
			{
				return;
			}
			idleTimer = Random.Range(4f, 10f);
			if (!(Random.value >= 0.55f))
			{
				Vector3 val = NoY(nav.Position - around);
				float num = Mathf.Atan2(val.x, val.z) * 57.29578f + Random.Range(-70f, 70f);
				float num2 = Random.Range(min + 0.5f, Mathf.Max(min + 1f, max - 1.5f));
				Vector3 target = around + Quaternion.Euler(0f, num, 0f) * Vector3.forward * num2;
				if (nav.CanReach(target, 2f, out var pathLength) && pathLength < max * 2f)
				{
					nav.SetDestination(target);
				}
			}
		}

		private List<PlayerDeathHead> DeadHeads()
		{
			deadHeads.Clear();
			List<PlayerAvatar> list = (((Object)(object)GameDirector.instance != (Object)null) ? GameDirector.instance.PlayerList : null);
			if (list != null)
			{
				foreach (PlayerAvatar item in list)
				{
					if ((Object)(object)item != (Object)null && item.isDisabled && (Object)(object)item.playerDeathHead != (Object)null && (Object)(object)item.playerDeathHead.physGrabObject != (Object)null)
					{
						deadHeads.Add(item.playerDeathHead);
					}
				}
			}
			return deadHeads;
		}

		private PlayerDeathHead NearestHead(Func<PlayerDeathHead, bool> needsWork, Vector3 from)
		{
			//IL_0032: 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)
			PlayerDeathHead result = null;
			float num = float.MaxValue;
			foreach (PlayerDeathHead deadHead in deadHeads)
			{
				if (needsWork(deadHead))
				{
					float num2 = Vector3.Distance(((Component)deadHead.physGrabObject).transform.position, from);
					if (num2 < num)
					{
						num = num2;
						result = deadHead;
					}
				}
			}
			return result;
		}

		private static string HeadName(PlayerDeathHead head)
		{
			if (SemiFunc.IsMultiplayer() && (Object)(object)head.playerAvatar != (Object)null && !head.playerAvatar.isLocal && !string.IsNullOrEmpty(head.playerAvatar.playerName))
			{
				return head.playerAvatar.playerName + "'s";
			}
			return "your";
		}

		private static float CollectRange()
		{
			if (!Plugin.Scouting.Value)
			{
				return Plugin.CollectRadius.Value;
			}
			return Mathf.Max(Plugin.CollectRadius.Value, Plugin.ScoutRadius.Value);
		}

		private void Explore()
		{
			//IL_0020: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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_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_0055: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < 6; i++)
			{
				Vector3 val = Quaternion.Euler(0f, Random.Range(0f, 360f), 0f) * Vector3.forward;
				Vector3 point = nav.Position + val * Random.Range(8f, 18f);
				if (nav.Sample(point, 3f, out var result) && nav.CanReach(result, 1f, out var pathLength) && pathLength < 40f)
				{
					nav.SetDestination(result, 1f);
					break;
				}
			}
		}

		private ExtractionPoint PickExtraction()
		{
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			RoundDirector instance = RoundDirector.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			ExtractionPoint extractionPointCurrent = instance.extractionPointCurrent;
			if ((Object)(object)extractionPointCurrent != (Object)null && instance.extractionPointActive && !extractionPointCurrent.StateIs((State)1) && !extractionPointCurrent.StateIs((State)7))
			{
				return extractionPointCurrent;
			}
			if (instance.allExtractionPointsCompleted || instance.extractionPointList == null)
			{
				return null;
			}
			ExtractionPoint result = null;
			float num = float.MaxValue;
			foreach (GameObject extractionPoint in instance.extractionPointList)
			{
				ExtractionPoint val = (((Object)(object)extractionPoint != (Object)null) ? extractionPoint.GetComponent<ExtractionPoint>() : null);
				if (!((Object)(object)val == (Object)null) && !val.isShop && !val.isLocked && val.StateIs((State)1))
				{
					Vector3 val2 = ExtractionCenter(val);
					float pathLength;
					float num2 = (nav.CanReach(val2, 4f, out pathLength) ? pathLength : (Vector3.Distance(nav.Position, val2) * 2f + 50f));
					if (num2 < num)
					{
						num = num2;
						result = val;
					}
				}
			}
			return result;
		}

		private static Vector3 ExtractionCenter(ExtractionPoint point)
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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_00b3: 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_0077: 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_0086: 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_003a: 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_004a: 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: Unknown result type (might be due to invalid IL or missing references)
			RoomVolume[] componentsInChildren = ((Component)point).GetComponentsInChildren<RoomVolume>(true);
			foreach (RoomVolume val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null && val.Extraction)
				{
					Collider component = ((Component)val).GetComponent<Collider>();
					if ((Object)(object)component != (Object)null)
					{
						Bounds bounds = component.bounds;
						return new Vector3(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).min.y + 0.8f, ((Bounds)(ref bounds)).center.z);
					}
					return ((Component)val).transform.position + Vector3.up * 0.8f;
				}
			}
			return ((Component)point).transform.position + Vector3.up * 0.8f;
		}

		private static bool HaulGoalMet(ExtractionPoint point)
		{
			if (point.StateIs((State)2) && point.haulGoal > 0)
			{
				return point.haulGoal - point.haulCurrent <= 0;
			}
			return false;
		}

		private void ActivateExtraction(ExtractionPoint point)
		{
			if (LastStanding && !((Object)(object)point == (Object)null) && !point.isLocked && point.StateIs((State)1))
			{
				Plugin.Log.LogInfo((object)"Gruffy is the last one standing: activating an extraction point.");
				point.OnClick();
			}
		}

		private void UpdatePressConfirm(ref bool sprinting)
		{
			//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_004f: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_0071: 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_0088: 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)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			if (!LastStanding || (Object)(object)heroExtraction == (Object)null || (Object)(object)confirmButton == (Object)null || !HaulGoalMet(heroExtraction))
			{
				SetState(State.Follow);
				return;
			}
			Vector3 position = confirmButton.transform.position;
			nav.SetDestination(position);
			Vector3 val = NoY(position - nav.Position);
			sprinting = ((Vector3)(ref val)).magnitude > 6f;
			if (!(Vector3.Distance(position, nav.Position + Vector3.up) < 2.2f))
			{
				if (stateTimer > 3f)
				{
					val = NoY(position - nav.Position);
					if (((Vector3)(ref val)).magnitude < 2.5f)
					{
						goto IL_00d5;
					}
				}
				if (stateTimer > 15f)
				{
					confirmCooldown = 4f;
					SetState(State.Follow);
				}
				return;
			}
			goto IL_00d5;
			IL_00d5:
			if (GruffyCompat.PressConfirmButton(confirmButton))
			{
				Plugin.Log.LogInfo((object)"Gruffy is the last one standing: pressed the extraction confirm button.");
				voice.SayText("Cash out! Cash out! Come back to me!");
			}
			confirmCooldown = 4f;
			SetState(State.Follow);
		}

		private void StartFetch(PhysGrabObject target, ValuableObject valuable, Delivery where)
		{
			seekGrab = target;
			seekValuable = valuable;
			delivery = where;
			SetState(State.Seek);
			seekGrab = target;
			seekValuable = valuable;
		}

		private ValuableObject FindValuable(Vector3 around, float radius, string sizes)
		{
			//IL_0075: 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_007c: 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_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: 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)
			//IL_00a5: 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)
			if ((Object)(object)ValuableDirector.instance == (Object)null || ValuableDirector.instance.valuableList == null)
			{
				return null;
			}
			string allowedSizes = sizes ?? string.Empty;
			float time = Time.time;
			ValuableObject val = null;
			float num = float.MaxValue;
			foreach (ValuableObject valuable in ValuableDirector.instance.valuableList)
			{
				if (!IsKnown(valuable) || !IsCollectable(valuable, allowedSizes, time))
				{
					continue;
				}
				Vector3 worldCenterOfMass = valuable.physGrabObject.rb.worldCenterOfMass;
				float num2 = Vector3.Distance(worldCenterOfMass, around);
				if (!(num2 > radius) && !(Mathf.Abs(worldCenterOfMass.y - around.y) > 4f))
				{
					float num3 = Vector3.Distance(worldCenterOfMass, nav.Position) + num2 * 0.5f;
					if (num3 < num)
					{
						num = num3;
						val = valuable;
					}
				}
			}
			if ((Object)(object)val != (Object)null && !nav.CanReach(val.physGrabObject.rb.worldCenterOfMass, 1.8f, out var _))
			{
				Blacklist(val.physGrabObject, 30f);
				return null;
			}
			return val;
		}

		private bool IsCollectable(ValuableObject valuable, string allowedSizes, float now)
		{
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)valuable == (Object)null || !((Component)valuable).gameObject.activeInHierarchy)
			{
				return false;
			}
			if (!IsGrabbable(valuable.physGrabObject, now))
			{
				return false;
			}
			PhysGrabObject physGrabObject = valuable.physGrabObject;
			PhysGrabCart val = CartHolding(physGrabObject);
			if (((Object)(object)val != (Object)null || ((Object)(object)physGrabObject.impactDetector != (Object)null && physGrabObject.impactDetector.inCart)) && (!LastStanding || !((Object)(object)val != (Object)null) || !IsStuckCart(val)))
			{
				return false;
			}
			if ((Object)(object)valuable.roomVolumeCheck != (Object)null && (valuable.roomVolumeCheck.inExtractionPoint || valuable.roomVolumeCheck.inTruck))
			{
				return false;
			}
			if (allowedSizes.IndexOf(((object)Unsafe.As<Type, Type>(ref valuable.volumeType)/*cast due to .constrained prefix*/).ToString(), StringComparison.OrdinalIgnoreCase) < 0)
			{
				return false;
			}
			if (threatActive)
			{
				return Vector3.Distance(physGrabObject.rb.position, threatPosition) > 6f;
			}
			return true;
		}

		private bool IsGrabbable(PhysGrabObject grab, float now)
		{
			if ((Object)(object)grab == (Object)null || (Object)(object)grab.rb == (Object)null || grab.dead || grab.rb.isKinematic || !((Component)grab).gameObject.activeInHierarchy)
			{
				return false;
			}
			if (grab.playerGrabbing != null && grab.playerGrabbing.Count > 0)
			{
				return false;
			}
			if (blacklist.TryGetValue(((Object)grab).GetInstanceID(), out var value))
			{
				return !(now < value);
			}
			return true;
		}

		private void Blacklist(PhysGrabObject grab, float seconds)
		{
			if ((Object)(object)grab != (Object)null)
			{
				blacklist[((Object)grab).GetInstanceID()] = Time.time + seconds;
			}
		}

		private void UpdateSeek(Vector3 playerPos, ref bool sprinting)
		{
			//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_0095: 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_00a4: 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_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: 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_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_029b: 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_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: 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_0233: 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_0239: 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)
			if (!(((Object)(object)seekValuable != (Object)null) ? IsCollectable(seekValuable, (delivery == Delivery.CartOrPlayer) ? (Plugin.CollectSizes.Value ?? string.Empty) : "Tiny,Small,Medium,Big,Wide,Tall,VeryTall", Time.time) : IsGrabbable(seekGrab, Time.time)))
			{
				SetState(State.Follow);
				return;
			}
			if (hingeWaitTimer > 0f)
			{
				hingeWaitTimer -= Time.deltaTime;
				return;
			}
			Vector3 worldCenterOfMass = seekGrab.rb.worldCenterOfMass;
			Vector3 val = nav.Position + Vector3.up * 1.2f;
			float num = Vector3.Distance(val, worldCenterOfMass);
			Vector3 val2 = NoY(worldCenterOfMass - nav.Position);
			float magnitude = ((Vector3)(ref val2)).magnitude;
			sprinting = magnitude > 8f || (delivery != Delivery.CartOrPlayer && magnitude > 4f);
			bool lastStanding = LastStanding;
			if (num < 4f)
			{
				if (!FindBlocker(val, worldCenterOfMass, seekGrab, out var blocker))
				{
					if (num < 3.2f)
					{
						carrier.Begin(seekGrab, seekValuable);
						fragileLineSaid = false;
						lostGripTimer = 0f;
						releaseHoldTimer = 0f;
						hingeAttempts = 0;
						SetState(State.Carry);
						if ((Object)(object)seekValuable != (Object)null)
						{
							voice.Say(SpeechType.PickUp, 0.5f, 10f);
						}
						else if (lastStanding)
						{
							HeroStatus("grabbed your head");
						}
						return;
					}
				}
				else
				{
					PhysGrabHinge componentInParent = ((Component)((RaycastHit)(ref blocker)).collider).GetComponentInParent<PhysGrabHinge>();
					if ((Object)(object)componentInParent != (Object)null && !componentInParent.dead && !componentInParent.broken && hingeAttempts < 4 && Vector3.Distance(val, ((RaycastHit)(ref blocker)).point) < 3.5f)
					{
						if ((Object)(object)componentInParent != (Object)(object)lastHinge)
						{
							lastHinge = componentInParent;
							hingeAttempts = 0;
						}
						hingeAttempts++;
						carrier.PullHinge(((Component)componentInParent).GetComponent<Rigidbody>(), ((RaycastHit)(ref blocker)).point, val + Vector3.up * 0.2f, 0.9f);
						hingeWaitTimer = 1.1f;
						nav.Stop();
						Plugin.Debug($"Gruffy is opening {((Object)componentInParent).name} to reach {((Object)seekGrab).name} (try {hingeAttempts}).");
						return;
					}
				}
			}
			GoTo(worldCenterOfMass, 1.8f);
			bool flag = delivery == Delivery.CartOrPlayer && Vector3.Distance(nav.Position, playerPos) > CollectRange() * 1.5f;
			bool flag2 = stateTimer > (lastStanding ? 60f : 15f);
			bool flag3 = !lastStanding && (nav.PathFailed || nav.StuckCount >= 2);
			bool flag4 = hingeAttempts >= 4 && num < 4f;
			if (flag2 || flag3 || flag || flag4)
			{
				Plugin.Debug($"Gruffy gave up on {((Object)seekGrab).name} (timeout {flag2}, path {flag3}, far {flag}, blocked {flag4}).");
				Blacklist(seekGrab, ((Object)(object)seekValuable != (Object)null) ? 30f : 3f);
				hingeAttempts = 0;
				SetState(State.Follow);
			}
		}

		private bool FindBlocker(Vector3 from, Vector3 to, PhysGrabObject target, out RaycastHit blocker)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: 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)
			blocker = default(RaycastHit);
			Vector3 val = to - from;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude < 0.05f)
			{
				return false;
			}
			int mask = LayerMask.GetMask(new string[3] { "Default", "PhysGrabObject", "PhysGrabObjectHinge" });
			int num = Physics.RaycastNonAlloc(from, val / magnitude, rayBuffer, magnitude, mask, (QueryTriggerInteraction)1);
			float num2 = float.MaxValue;
			bool result = false;
			for (int i = 0; i < num; i++)
			{
				RaycastHit val2 = rayBuffer[i];
				if (!((Object)(object)((RaycastHit)(ref val2)).collider == (Object)null) && !(((RaycastHit)(ref val2)).distance >= num2))
				{
					PhysGrabObject componentInParent = ((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent<PhysGrabObject>();
					if (!((Object)(object)componentInParent != (Object)null) || !((Object)(object)componentInParent == (Object)(object)target))
					{
						num2 = ((RaycastHit)(ref val2)).distance;
						blocker = val2;
						result = true;
					}
				}
			}
			return result;
		}

		private void GoTo(Vector3 target, float sampleRadius)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			nav.SetDestination(target, sampleRadius);
			if (nav.PathFailed && Vector3.Distance(nav.Position, target) < 8f && !Physics.Linecast(nav.Position + Vector3.up * 0.5f, target, LayerMask.GetMask(new string[1] { "Default" }), (QueryTriggerInteraction)1))
			{
				nav.SetDirect(target);
			}
		}

		private void HandleUnreachable()
		{
			//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_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)
			//IL_00d1: 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_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: 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_0189: 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_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: 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_010c: 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)
			if ((Object)(object)carrier.TowCart != (Object)null || state == State.Tow)
			{
				unreachableTimer = 0f;
				return;
			}
			bool flag = nav.HasDestination && (nav.PathFailed || nav.StuckCount >= 2 || (!nav.HasPath && nav.PathIsPartial));
			unreachableTimer = (flag ? (unreachableTimer + Time.deltaTime) : 0f);
			if (unreachableTimer < 5f)
			{
				return;
			}
			unreachableTimer = 0f;
			Vector3 destination = nav.Destination;
			bool lastStanding = LastStanding;
			for (float num = 0f; num <= 0.75f; num += 0.25f)
			{
				Vector3 point = Vector3.Lerp(destination, nav.Position, num);
				if (!nav.Sample(point, 3f, out var result) || Vector3.Distance(result, nav.Position) < 2f || (!lastStanding && IsOnScreen(result + Vector3.up)))
				{
					continue;
				}
				Plugin.Log.LogInfo((object)$"Gruffy couldn't find a way to {destination}; hopping to {result}.");
				carrier.Release(stopObject: false);
				nav.Warp(result);
				try
				{
					CameraGlitch instance = CameraGlitch.Instance;
					if (instance != null)
					{
						instance.PlayTiny();
					}
					return;
				}
				catch
				{
					return;
				}
			}
			if (lastStanding)
			{
				HeroStatus($"stuck: no walkable spot near {destination}");
			}
		}

		private void HeroStatus(string status)
		{
			if (status != lastHeroStatus)
			{
				lastHeroStatus = status;
				Plugin.Log.LogInfo((object)(Plugin.Stamp() + " [hero] Gruffy: " + status));
			}
		}

		private void UpdateCarry(Vector3 playerPos, ref float speed, ref bool sprinting)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: 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_0070: 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_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0368: 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)
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_0341: Unknown result type (might be due to invalid IL or missing references)
			//IL_0346: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0351: Unknown result type (might be due to invalid IL or missing references)
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0381: Unknown result type (might be due to invalid IL or missing references)
			//IL_0382: Unknown result type (might be due to invalid IL or missing references)
			//IL_0387: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: 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_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c4: 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_0129: 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_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_03be: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bf: 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_03ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cc: Unknown result type (might be due to invalid IL or