Decompiled source of GambitEnhancements v1.0.0

GambitEnhancements.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("REPOJP")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("REPOJP")]
[assembly: AssemblyTitle("REPOJP")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace REPOJP.GambitEnhancements
{
	[BepInPlugin("REPOJP.GambitEnhancements", "GambitEnhancements", "1.0.0")]
	public sealed class GambitEnhancementsPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "REPOJP.GambitEnhancements";

		public const string PluginName = "GambitEnhancements";

		public const string PluginVersion = "1.0.0";

		internal static GambitEnhancementsPlugin Instance;

		internal static ManualLogSource Log;

		private Harmony _harmony;

		internal static ConfigEntry<bool> EnableMod;

		internal static ConfigEntry<bool> EnableVerboseLog;

		internal static ConfigEntry<int> RouletteDurationSeconds;

		internal static ConfigEntry<bool> ForceCarryToGoalAfterRoulette;

		internal static ConfigEntry<float> ReleaseGrabDistance;

		internal static ConfigEntry<bool> RunAwayDuringRoulette;

		internal static ConfigEntry<float> RouletteRunSpeed;

		internal static ConfigEntry<float> RouletteRunAcceleration;

		internal static ConfigEntry<float> GoalReachedDistance;

		internal static ConfigEntry<float> EscapeDestinationRefreshInterval;

		internal static ConfigEntry<bool> StrengthenPlayerLockDuringRoulette;

		internal static ConfigEntry<float> RouletteFollowForceMultiplier;

		internal static ConfigEntry<float> RouletteFollowForceGrabbedMultiplier;

		internal static ConfigEntry<float> RouletteLockLerpSpeed;

		internal static ConfigEntry<bool> ImmuneToStunDuringRoulette;

		internal static ConfigEntry<bool> BlockStunSetCallDuringRoulette;

		internal static ConfigEntry<bool> EnableJumpAssistDuringRoulette;

		internal static ConfigEntry<float> JumpAssistInterval;

		internal static ConfigEntry<float> StuckVelocityThreshold;

		internal static ConfigEntry<float> StuckDistanceThreshold;

		internal static ConfigEntry<float> StuckRepathDelay;

		internal static ConfigEntry<bool> InstantRepathWhenStuck;

		internal static ConfigEntry<float> SameGoalReapplyInterval;

		private void Awake()
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Expected O, but got Unknown
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Expected O, but got Unknown
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Expected O, but got Unknown
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Expected O, but got Unknown
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Expected O, but got Unknown
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Expected O, but got Unknown
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Expected O, but got Unknown
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Expected O, but got Unknown
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Expected O, but got Unknown
			//IL_0382: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Expected O, but got Unknown
			//IL_03bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c9: Expected O, but got Unknown
			//IL_03fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0406: Expected O, but got Unknown
			//IL_0439: Unknown result type (might be due to invalid IL or missing references)
			//IL_0443: Expected O, but got Unknown
			//IL_0496: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a0: Expected O, but got Unknown
			//IL_04ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b5: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			((Component)this).transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			EnableMod = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableMod", true, "Enable or disable this mod");
			EnableVerboseLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Logging", "EnableVerboseLog", true, "Enable verbose logs");
			RouletteDurationSeconds = ((BaseUnityPlugin)this).Config.Bind<int>("Roulette", "RouletteDurationSeconds", 10, new ConfigDescription("Roulette duration in whole seconds", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10), Array.Empty<object>()));
			ForceCarryToGoalAfterRoulette = ((BaseUnityPlugin)this).Config.Bind<bool>("Roulette", "ForceCarryToGoalAfterRoulette", true, "Keep dragging the grabbed player to the selected farthest destination even after roulette has ended");
			ReleaseGrabDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Roulette", "ReleaseGrabDistance", 4.999999f, new ConfigDescription("Release the grabbed player if Gambit and the target become farther apart than this distance", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>()));
			RunAwayDuringRoulette = ((BaseUnityPlugin)this).Config.Bind<bool>("Movement", "RunAwayDuringRoulette", true, "Run away during roulette");
			RouletteRunSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "RouletteRunSpeed", 6f, new ConfigDescription("Run speed during roulette or forced carry", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>()));
			RouletteRunAcceleration = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "RouletteRunAcceleration", 12f, new ConfigDescription("Run acceleration during roulette or forced carry", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>()));
			GoalReachedDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "GoalReachedDistance", 5f, new ConfigDescription("Distance at which the farthest destination is considered reached", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 10f), Array.Empty<object>()));
			EscapeDestinationRefreshInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "EscapeDestinationRefreshInterval", 3f, new ConfigDescription("Reserved compatibility setting for destination refresh interval", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 30f), Array.Empty<object>()));
			StrengthenPlayerLockDuringRoulette = ((BaseUnityPlugin)this).Config.Bind<bool>("Grab", "StrengthenPlayerLockDuringRoulette", true, "Strengthen player lock during roulette and forced carry");
			RouletteFollowForceMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Grab", "RouletteFollowForceMultiplier", 1f, new ConfigDescription("Follow force multiplier while target is not grabbed by another player", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			RouletteFollowForceGrabbedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Grab", "RouletteFollowForceGrabbedMultiplier", 3f, new ConfigDescription("Follow force multiplier while target is grabbed by another player", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			RouletteLockLerpSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Grab", "RouletteLockLerpSpeed", 6f, new ConfigDescription("Lock lerp speed during roulette and forced carry", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>()));
			ImmuneToStunDuringRoulette = ((BaseUnityPlugin)this).Config.Bind<bool>("Stun", "ImmuneToStunDuringRoulette", true, "Prevent stun during roulette only");
			BlockStunSetCallDuringRoulette = ((BaseUnityPlugin)this).Config.Bind<bool>("Stun", "BlockStunSetCallDuringRoulette", true, "Block EnemyStateStunned.Set during roulette only");
			EnableJumpAssistDuringRoulette = ((BaseUnityPlugin)this).Config.Bind<bool>("Assist", "EnableJumpAssistDuringRoulette", true, "Enable jump assist during roulette and forced carry");
			JumpAssistInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Assist", "JumpAssistInterval", 0.5f, new ConfigDescription("Jump assist call interval", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.02f, 5f), Array.Empty<object>()));
			StuckVelocityThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Assist", "StuckVelocityThreshold", 0.15f, new ConfigDescription("Velocity threshold for stuck detection", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 3f), Array.Empty<object>()));
			StuckDistanceThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Assist", "StuckDistanceThreshold", 2f, new ConfigDescription("Distance threshold for stuck detection", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>()));
			StuckRepathDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Assist", "StuckRepathDelay", 0.2f, new ConfigDescription("Delay before stronger stuck recovery starts", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 5f), Array.Empty<object>()));
			InstantRepathWhenStuck = ((BaseUnityPlugin)this).Config.Bind<bool>("Assist", "InstantRepathWhenStuck", true, "When stuck, reapply the same goal and trigger stronger recovery");
			SameGoalReapplyInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Assist", "SameGoalReapplyInterval", 5f, new ConfigDescription("Minimum interval between same-goal reapply operations while stuck", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 30f), Array.Empty<object>()));
			_harmony = new Harmony("REPOJP.GambitEnhancements");
			_harmony.PatchAll();
			Log.LogInfo((object)"GambitEnhancements 1.0.0 loaded");
		}

		private void OnDestroy()
		{
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}

		internal static bool ModEnabled()
		{
			return EnableMod.Value;
		}

		internal static void Verbose(string message)
		{
			if (EnableVerboseLog.Value && Log != null)
			{
				Log.LogInfo((object)message);
			}
		}
	}
	internal static class GambitEnhancementsCore
	{
		private sealed class SpinnyRuntimeState
		{
			public bool GrabValuesStored;

			public float OriginalFollowForceMultiplier;

			public float OriginalFollowForceGrabbedMultiplier;

			public float OriginalLockLerpSpeed;

			public bool WasRouletteGoingOn;

			public bool GoalCaptured;

			public bool GoalActive;

			public bool PersistCarryActive;

			public Vector3 StartPosition;

			public Vector3 GoalDestination;

			public float StuckTimer;

			public float JumpAssistTimer;

			public float SameGoalReapplyTimer;
		}

		private static readonly FieldInfo SpinnyFieldFollowForceGrabbedMultiplier = AccessTools.Field(typeof(EnemySpinny), "_followForceGrabbedMultiplier");

		private static readonly FieldInfo SpinnyFieldLockLerpSpeed = AccessTools.Field(typeof(EnemySpinny), "lockLerpSpeed");

		private static readonly FieldInfo EnemyRigidbodyFieldRb = AccessTools.Field(typeof(EnemyRigidbody), "rb");

		private static readonly FieldInfo EnemyJumpFieldJumping = AccessTools.Field(typeof(EnemyJump), "jumping");

		private static readonly MethodInfo SpinnyMethodJumpIfStuck = AccessTools.Method(typeof(EnemySpinny), "JumpIfStuck", new Type[1] { typeof(bool) }, (Type[])null);

		private static readonly MethodInfo SpinnyMethodLockInPlayer = AccessTools.Method(typeof(EnemySpinny), "LockInPlayer", new Type[2]
		{
			typeof(bool),
			typeof(bool)
		}, (Type[])null);

		private static readonly MethodInfo SpinnyMethodUpdateState = AccessTools.Method(typeof(EnemySpinny), "UpdateState", new Type[1] { typeof(State) }, (Type[])null);

		private static readonly Dictionary<int, SpinnyRuntimeState> RuntimeStates = new Dictionary<int, SpinnyRuntimeState>();

		internal static void PostUpdate(EnemySpinny spinny)
		{
			if (!CanControl(spinny))
			{
				RestoreAndDisable(spinny);
				return;
			}
			SpinnyRuntimeState runtime = GetRuntime(spinny);
			UpdateGoalState(spinny, runtime);
			if (spinny.RouletteGoingOn())
			{
				spinny.spinDurationSeconds = Mathf.Clamp(GambitEnhancementsPlugin.RouletteDurationSeconds.Value, 0, 10);
			}
			if (ShouldMaintainGrab(spinny, runtime) && IsTargetTooFar(spinny))
			{
				ReleaseGrab(spinny, runtime);
			}
			if (ShouldMaintainGrab(spinny, runtime))
			{
				if (GambitEnhancementsPlugin.StrengthenPlayerLockDuringRoulette.Value)
				{
					ApplyGrabSettings(spinny, runtime);
				}
			}
			else
			{
				RestoreGrabSettings(spinny, runtime);
			}
			if (spinny.RouletteGoingOn() && GambitEnhancementsPlugin.ImmuneToStunDuringRoulette.Value)
			{
				ClearStun(spinny);
			}
			if (ShouldMaintainMovement(spinny, runtime))
			{
				ApplyMovement(spinny, runtime);
			}
		}

		internal static void PostFixedUpdate(EnemySpinny spinny)
		{
			if (!CanControl(spinny))
			{
				RestoreAndDisable(spinny);
				return;
			}
			SpinnyRuntimeState runtime = GetRuntime(spinny);
			UpdateGoalState(spinny, runtime);
			if (ShouldMaintainGrab(spinny, runtime) && !IsTargetTooFar(spinny))
			{
				InvokeLockInPlayer(spinny, horizontalPull: false, fixedUpdate: true);
			}
		}

		internal static bool ShouldBlockStun(EnemyStateStunned stunnedComponent)
		{
			if (!GambitEnhancementsPlugin.ModEnabled())
			{
				return false;
			}
			if (!GambitEnhancementsPlugin.BlockStunSetCallDuringRoulette.Value)
			{
				return false;
			}
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return false;
			}
			EnemySpinny component = ((Component)stunnedComponent).GetComponent<EnemySpinny>();
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			return component.RouletteGoingOn();
		}

		private static void UpdateGoalState(EnemySpinny spinny, SpinnyRuntimeState runtime)
		{
			//IL_0057: 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_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_006d: 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_019f: 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)
			if ((Object)(object)spinny.playerTarget == (Object)null || spinny.playerTarget.isDisabled)
			{
				runtime.GoalActive = false;
				runtime.GoalCaptured = false;
				runtime.PersistCarryActive = false;
				return;
			}
			if (spinny.RouletteGoingOn() && !runtime.WasRouletteGoingOn)
			{
				runtime.StartPosition = GetCurrentPosition(spinny);
				runtime.GoalDestination = GetFarthestPointFromPosition(runtime.StartPosition);
				runtime.GoalActive = true;
				runtime.GoalCaptured = true;
				runtime.PersistCarryActive = false;
				runtime.StuckTimer = 0f;
				runtime.JumpAssistTimer = 0f;
				runtime.SameGoalReapplyTimer = 0f;
				GambitEnhancementsPlugin.Verbose($"[GambitEnhancements] Goal locked -> {runtime.GoalDestination}");
			}
			if (!spinny.RouletteGoingOn() && runtime.WasRouletteGoingOn)
			{
				if (runtime.GoalCaptured && GambitEnhancementsPlugin.ForceCarryToGoalAfterRoulette.Value && (Object)(object)spinny.playerTarget != (Object)null && !spinny.playerTarget.isDisabled && !IsGoalReached(spinny, runtime))
				{
					runtime.PersistCarryActive = true;
					runtime.GoalActive = true;
					GambitEnhancementsPlugin.Verbose($"[GambitEnhancements] Persist carry enabled -> {runtime.GoalDestination}");
				}
				else
				{
					runtime.PersistCarryActive = false;
				}
			}
			if (runtime.GoalActive && IsGoalReached(spinny, runtime))
			{
				runtime.GoalActive = false;
				runtime.PersistCarryActive = false;
				runtime.StuckTimer = 0f;
				runtime.JumpAssistTimer = 0f;
				runtime.SameGoalReapplyTimer = 0f;
				GambitEnhancementsPlugin.Verbose($"[GambitEnhancements] Goal reached -> {runtime.GoalDestination}");
			}
			runtime.WasRouletteGoingOn = spinny.RouletteGoingOn();
		}

		private static bool ShouldMaintainMovement(EnemySpinny spinny, SpinnyRuntimeState runtime)
		{
			if (!GambitEnhancementsPlugin.RunAwayDuringRoulette.Value)
			{
				return false;
			}
			if (spinny.RouletteGoingOn() && runtime.GoalActive)
			{
				return true;
			}
			if (runtime.PersistCarryActive && runtime.GoalActive)
			{
				return true;
			}
			return false;
		}

		private static bool ShouldMaintainGrab(EnemySpinny spinny, SpinnyRuntimeState runtime)
		{
			if (spinny.RouletteGoingOn())
			{
				return true;
			}
			if (runtime.PersistCarryActive && runtime.GoalActive)
			{
				return true;
			}
			return false;
		}

		private static void ApplyMovement(EnemySpinny spinny, SpinnyRuntimeState runtime)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			Enemy component = ((Component)spinny).GetComponent<Enemy>();
			EnemyNavMeshAgent component2 = ((Component)spinny).GetComponent<EnemyNavMeshAgent>();
			EnemyRigidbody component3 = ((Component)spinny).GetComponent<EnemyRigidbody>();
			EnemyJump component4 = ((Component)spinny).GetComponent<EnemyJump>();
			if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || !runtime.GoalActive)
			{
				return;
			}
			float num = Time.deltaTime;
			if (num <= 0f)
			{
				num = 0.0166667f;
			}
			Vector3 currentPosition = GetCurrentPosition(spinny);
			Rigidbody enemyRigidBody = GetEnemyRigidBody(component3);
			component2.SetDestination(runtime.GoalDestination);
			component2.OverrideAgent(GambitEnhancementsPlugin.RouletteRunSpeed.Value, GambitEnhancementsPlugin.RouletteRunAcceleration.Value, 0.25f);
			if (runtime.SameGoalReapplyTimer > 0f)
			{
				runtime.SameGoalReapplyTimer -= num;
			}
			bool flag = IsLikelyStuck(currentPosition, enemyRigidBody, runtime);
			if (flag)
			{
				runtime.StuckTimer += num;
			}
			else
			{
				runtime.StuckTimer = 0f;
			}
			if (GambitEnhancementsPlugin.InstantRepathWhenStuck.Value && flag && runtime.StuckTimer >= GambitEnhancementsPlugin.StuckRepathDelay.Value && runtime.SameGoalReapplyTimer <= 0f)
			{
				runtime.SameGoalReapplyTimer = GambitEnhancementsPlugin.SameGoalReapplyInterval.Value;
				component2.SetDestination(runtime.GoalDestination);
				component2.OverrideAgent(GambitEnhancementsPlugin.RouletteRunSpeed.Value, GambitEnhancementsPlugin.RouletteRunAcceleration.Value, 0.25f);
				GambitEnhancementsPlugin.Verbose($"[GambitEnhancements] Reapply same goal -> {runtime.GoalDestination}");
			}
			if (!GambitEnhancementsPlugin.EnableJumpAssistDuringRoulette.Value)
			{
				return;
			}
			runtime.JumpAssistTimer -= num;
			if (runtime.JumpAssistTimer <= 0f)
			{
				runtime.JumpAssistTimer = GambitEnhancementsPlugin.JumpAssistInterval.Value;
				InvokeJumpIfStuck(spinny);
				if (flag)
				{
					ForceStuckJump(component4, currentPosition, runtime.GoalDestination);
				}
			}
		}

		private static void ClearStun(EnemySpinny spinny)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Invalid comparison between Unknown and I4
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			Enemy component = ((Component)spinny).GetComponent<Enemy>();
			EnemyStateStunned component2 = ((Component)spinny).GetComponent<EnemyStateStunned>();
			if (!((Object)(object)component2 == (Object)null))
			{
				component2.OverrideDisable(0.3f);
				component2.stunTimer = 0f;
				if ((Object)(object)component != (Object)null && (int)component.CurrentState == 9)
				{
					component.CurrentState = (EnemyState)2;
				}
			}
		}

		private static void ReleaseGrab(EnemySpinny spinny, SpinnyRuntimeState runtime)
		{
			RestoreGrabSettings(spinny, runtime);
			runtime.GoalActive = false;
			runtime.PersistCarryActive = false;
			runtime.StuckTimer = 0f;
			runtime.JumpAssistTimer = 0f;
			runtime.SameGoalReapplyTimer = 0f;
			spinny.playerTarget = null;
			if (SpinnyMethodUpdateState != null)
			{
				try
				{
					SpinnyMethodUpdateState.Invoke(spinny, new object[1] { (object)(State)12 });
				}
				catch (Exception arg)
				{
					GambitEnhancementsPlugin.Verbose($"[GambitEnhancements] UpdateState invoke failed: {arg}");
				}
			}
			GambitEnhancementsPlugin.Verbose("[GambitEnhancements] Grab released because target distance exceeded threshold");
		}

		private static bool IsTargetTooFar(EnemySpinny spinny)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)spinny.playerTarget == (Object)null)
			{
				return false;
			}
			Vector3 currentPosition = GetCurrentPosition(spinny);
			Vector3 position = ((Component)spinny.playerTarget).transform.position;
			float value = GambitEnhancementsPlugin.ReleaseGrabDistance.Value;
			Vector3 val = currentPosition - position;
			float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
			return sqrMagnitude > value * value;
		}

		private static Vector3 GetFarthestPointFromPosition(Vector3 startPosition)
		{
			//IL_001b: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			List<LevelPoint> list = SemiFunc.LevelPointsGetAll();
			if (list == null || list.Count == 0)
			{
				return startPosition + Vector3.forward * 5f;
			}
			float num = -1f;
			LevelPoint val = null;
			foreach (LevelPoint item in list)
			{
				if (!((Object)(object)item == (Object)null) && (!((Object)(object)item.Room != (Object)null) || !item.Room.Truck))
				{
					Vector3 val2 = startPosition - ((Component)item).transform.position;
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					if (sqrMagnitude > num)
					{
						num = sqrMagnitude;
						val = item;
					}
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				return ((Component)val).transform.position;
			}
			return startPosition + Vector3.forward * 5f;
		}

		private static bool IsGoalReached(EnemySpinny spinny, SpinnyRuntimeState runtime)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 currentPosition = GetCurrentPosition(spinny);
			float value = GambitEnhancementsPlugin.GoalReachedDistance.Value;
			Vector3 val = currentPosition - runtime.GoalDestination;
			float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
			return sqrMagnitude <= value * value;
		}

		private static Vector3 GetCurrentPosition(EnemySpinny spinny)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0059: Unknown result type (might be due to invalid IL or missing references)
			Enemy component = ((Component)spinny).GetComponent<Enemy>();
			if ((Object)(object)component != (Object)null && (Object)(object)component.Rigidbody != (Object)null && (Object)(object)((Component)component.Rigidbody).transform != (Object)null)
			{
				return ((Component)component.Rigidbody).transform.position;
			}
			return ((Component)spinny).transform.position;
		}

		private static void ApplyGrabSettings(EnemySpinny spinny, SpinnyRuntimeState runtime)
		{
			if (!runtime.GrabValuesStored)
			{
				runtime.OriginalFollowForceMultiplier = spinny._followForceMultiplier;
				runtime.OriginalFollowForceGrabbedMultiplier = GetPrivateFloat(spinny, SpinnyFieldFollowForceGrabbedMultiplier, 0.025f);
				runtime.OriginalLockLerpSpeed = GetPrivateFloat(spinny, SpinnyFieldLockLerpSpeed, 1f);
				runtime.GrabValuesStored = true;
			}
			spinny._followForceMultiplier = GambitEnhancementsPlugin.RouletteFollowForceMultiplier.Value;
			SetPrivateFloat(spinny, SpinnyFieldFollowForceGrabbedMultiplier, GambitEnhancementsPlugin.RouletteFollowForceGrabbedMultiplier.Value);
			SetPrivateFloat(spinny, SpinnyFieldLockLerpSpeed, GambitEnhancementsPlugin.RouletteLockLerpSpeed.Value);
		}

		private static void RestoreGrabSettings(EnemySpinny spinny, SpinnyRuntimeState runtime)
		{
			if (runtime.GrabValuesStored)
			{
				spinny._followForceMultiplier = runtime.OriginalFollowForceMultiplier;
				SetPrivateFloat(spinny, SpinnyFieldFollowForceGrabbedMultiplier, runtime.OriginalFollowForceGrabbedMultiplier);
				SetPrivateFloat(spinny, SpinnyFieldLockLerpSpeed, runtime.OriginalLockLerpSpeed);
				runtime.GrabValuesStored = false;
			}
		}

		private static void InvokeJumpIfStuck(EnemySpinny spinny)
		{
			if (SpinnyMethodJumpIfStuck == null)
			{
				return;
			}
			try
			{
				SpinnyMethodJumpIfStuck.Invoke(spinny, new object[1] { true });
			}
			catch (Exception arg)
			{
				GambitEnhancementsPlugin.Verbose($"[GambitEnhancements] JumpIfStuck invoke failed: {arg}");
			}
		}

		private static void InvokeLockInPlayer(EnemySpinny spinny, bool horizontalPull, bool fixedUpdate)
		{
			if (SpinnyMethodLockInPlayer == null)
			{
				return;
			}
			try
			{
				SpinnyMethodLockInPlayer.Invoke(spinny, new object[2] { horizontalPull, fixedUpdate });
			}
			catch (Exception arg)
			{
				GambitEnhancementsPlugin.Verbose($"[GambitEnhancements] LockInPlayer invoke failed: {arg}");
			}
		}

		private static void ForceStuckJump(EnemyJump enemyJump, Vector3 currentPosition, Vector3 destination)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)enemyJump == (Object)null) && !GetPrivateBool(enemyJump, EnemyJumpFieldJumping, fallback: false))
			{
				Vector3 val = destination - currentPosition;
				if (((Vector3)(ref val)).sqrMagnitude <= 0.0001f)
				{
					val = Vector3.forward;
				}
				enemyJump.StuckTrigger(((Vector3)(ref val)).normalized);
			}
		}

		private static bool IsLikelyStuck(Vector3 currentPosition, Rigidbody rb, SpinnyRuntimeState runtime)
		{
			//IL_003a: 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)
			float value = GambitEnhancementsPlugin.StuckVelocityThreshold.Value;
			float num = value * value;
			float velocitySqrMagnitude = GetVelocitySqrMagnitude(rb);
			if (velocitySqrMagnitude >= num)
			{
				return false;
			}
			float value2 = GambitEnhancementsPlugin.StuckDistanceThreshold.Value;
			float num2 = value2 * value2;
			Vector3 val = currentPosition - runtime.GoalDestination;
			float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
			return sqrMagnitude > num2;
		}

		private static Rigidbody GetEnemyRigidBody(EnemyRigidbody enemyRigidbody)
		{
			if ((Object)(object)enemyRigidbody == (Object)null || EnemyRigidbodyFieldRb == null)
			{
				return null;
			}
			try
			{
				object? value = EnemyRigidbodyFieldRb.GetValue(enemyRigidbody);
				return (Rigidbody)((value is Rigidbody) ? value : null);
			}
			catch
			{
				return null;
			}
		}

		private static float GetVelocitySqrMagnitude(Rigidbody rb)
		{
			//IL_0016: 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)
			if ((Object)(object)rb == (Object)null)
			{
				return 0f;
			}
			Vector3 velocity = rb.velocity;
			return ((Vector3)(ref velocity)).sqrMagnitude;
		}

		private static bool CanControl(EnemySpinny spinny)
		{
			if (!GambitEnhancementsPlugin.ModEnabled())
			{
				return false;
			}
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return false;
			}
			if ((Object)(object)spinny == (Object)null)
			{
				return false;
			}
			return true;
		}

		private static void RestoreAndDisable(EnemySpinny spinny)
		{
			if (RuntimeStates.TryGetValue(((Object)spinny).GetInstanceID(), out SpinnyRuntimeState value))
			{
				RestoreGrabSettings(spinny, value);
				value.GoalActive = false;
				value.GoalCaptured = false;
				value.PersistCarryActive = false;
				value.WasRouletteGoingOn = false;
				value.StuckTimer = 0f;
				value.JumpAssistTimer = 0f;
				value.SameGoalReapplyTimer = 0f;
			}
		}

		private static SpinnyRuntimeState GetRuntime(EnemySpinny spinny)
		{
			int instanceID = ((Object)spinny).GetInstanceID();
			if (!RuntimeStates.TryGetValue(instanceID, out SpinnyRuntimeState value))
			{
				value = new SpinnyRuntimeState();
				RuntimeStates[instanceID] = value;
			}
			return value;
		}

		private static float GetPrivateFloat(object instance, FieldInfo fieldInfo, float fallback)
		{
			if (instance == null || fieldInfo == null)
			{
				return fallback;
			}
			try
			{
				object value = fieldInfo.GetValue(instance);
				if (value is float)
				{
					return (float)value;
				}
			}
			catch
			{
			}
			return fallback;
		}

		private static void SetPrivateFloat(object instance, FieldInfo fieldInfo, float value)
		{
			if (instance == null || fieldInfo == null)
			{
				return;
			}
			try
			{
				fieldInfo.SetValue(instance, value);
			}
			catch (Exception arg)
			{
				GambitEnhancementsPlugin.Verbose($"[GambitEnhancements] Failed to set private float: {arg}");
			}
		}

		private static bool GetPrivateBool(object instance, FieldInfo fieldInfo, bool fallback)
		{
			if (instance == null || fieldInfo == null)
			{
				return fallback;
			}
			try
			{
				object value = fieldInfo.GetValue(instance);
				if (value is bool)
				{
					return (bool)value;
				}
			}
			catch
			{
			}
			return fallback;
		}
	}
	[HarmonyPatch(typeof(EnemySpinny), "Update")]
	internal static class EnemySpinnyUpdatePatch
	{
		private static void Postfix(EnemySpinny __instance)
		{
			GambitEnhancementsCore.PostUpdate(__instance);
		}
	}
	[HarmonyPatch(typeof(EnemySpinny), "FixedUpdate")]
	internal static class EnemySpinnyFixedUpdatePatch
	{
		private static void Postfix(EnemySpinny __instance)
		{
			GambitEnhancementsCore.PostFixedUpdate(__instance);
		}
	}
	[HarmonyPatch(typeof(EnemyStateStunned), "Set")]
	internal static class EnemyStateStunnedSetPatch
	{
		private static bool Prefix(EnemyStateStunned __instance, float time)
		{
			if (!GambitEnhancementsCore.ShouldBlockStun(__instance))
			{
				return true;
			}
			__instance.OverrideDisable(Mathf.Max(0.3f, time));
			__instance.stunTimer = 0f;
			GambitEnhancementsPlugin.Verbose("[GambitEnhancements] Blocked stun Set() during roulette");
			return false;
		}
	}
	[HarmonyPatch(typeof(EnemyStateStunned), "Update")]
	internal static class EnemyStateStunnedUpdatePatch
	{
		private static void Prefix(EnemyStateStunned __instance)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Invalid comparison between Unknown and I4
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if (GambitEnhancementsCore.ShouldBlockStun(__instance))
			{
				__instance.OverrideDisable(0.3f);
				__instance.stunTimer = 0f;
				Enemy component = ((Component)__instance).GetComponent<Enemy>();
				if ((Object)(object)component != (Object)null && (int)component.CurrentState == 9)
				{
					component.CurrentState = (EnemyState)2;
				}
			}
		}
	}
}