Decompiled source of RealisticRunning v1.6.11

RealisticRunning.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.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("SurvivalMovementExertion")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SurvivalMovementExertion")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("21978fe2-ee63-49ee-aad5-3609c97f40b0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace SurvivalMovementExertion;

internal sealed class AudioFadeEnvelope
{
	private float start;

	private float target;

	private float elapsed;

	public float Value { get; private set; }

	public float Step(float requestedTarget, float dt, float duration)
	{
		requestedTarget = Math.Max(0f, Math.Min(1f, requestedTarget));
		if (requestedTarget != target)
		{
			start = Value;
			target = requestedTarget;
			elapsed = 0f;
		}
		elapsed += Math.Max(0f, dt);
		float num = ((duration <= 0f) ? 1f : Math.Min(1f, elapsed / duration));
		float num2 = num * num * (3f - 2f * num);
		Value = start + (target - start) * num2;
		if (num >= 1f)
		{
			Value = target;
		}
		return Value;
	}

	public void Reset()
	{
		float num = (Value = 0f);
		start = (target = (elapsed = num));
	}
}
internal static class ExertionVisualDriver
{
	internal static float MapExertion(float percentage)
	{
		percentage = Math.Max(0f, Math.Min(100f, percentage));
		if (percentage <= 20f)
		{
			return percentage * 0.0165f;
		}
		if (percentage <= 40f)
		{
			return 0.33f + (percentage - 20f) * 0.0165f;
		}
		return 0.66f + (percentage - 40f) * 0.0056666667f;
	}

	internal static float Step(float current, float target, float deltaTime, float timeConstant)
	{
		float num = (float)(1.0 - Math.Exp((0f - Math.Max(0f, deltaTime)) / Math.Max(0.1f, timeConstant)));
		return current + (target - current) * num;
	}
}
[RequireComponent(typeof(Camera))]
public sealed class ExertionVisualRenderer : MonoBehaviour
{
	private static Shader peripheralShader;

	private Material material;

	private bool initializationAttempted;

	private float intensity;

	private readonly PeripheralMotionAwareness motionAwareness = new PeripheralMotionAwareness();

	private bool enableMotionAwareness;

	private float motionAwarenessStrength;

	private float motionClearRadius;

	public string MotionAwarenessStatus => motionAwareness.Status;

	public string Status { get; private set; } = "not initialized";

	public float SaturationMultiplier { get; private set; } = 1f;

	public int RenderedFrames { get; private set; }

	public void Configure(float sharedIntensity, float blurStrength, float clarityStrength, float clearRadius, float visualSaturation, bool enablePeripheralMotionAwareness = false, float peripheralMotionAwarenessStrength = 0.65f)
	{
		//IL_014a: 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_015d: Expected O, but got Unknown
		intensity = sharedIntensity;
		enableMotionAwareness = enablePeripheralMotionAwareness;
		motionAwarenessStrength = peripheralMotionAwarenessStrength;
		motionClearRadius = clearRadius;
		if (!enableMotionAwareness)
		{
			motionAwareness.Reset();
		}
		SaturationMultiplier = visualSaturation;
		if (!initializationAttempted)
		{
			initializationAttempted = true;
			try
			{
				if ((Object)(object)peripheralShader == (Object)null)
				{
					using Stream stream = typeof(ExertionVisualRenderer).Assembly.GetManifestResourceStream("RealisticRunning.exertionvisuals");
					if (stream == null)
					{
						throw new InvalidOperationException("Embedded visual shader bundle is missing.");
					}
					using BinaryReader binaryReader = new BinaryReader(stream);
					AssetBundle val = AssetBundle.LoadFromMemory(binaryReader.ReadBytes((int)stream.Length));
					if ((Object)(object)val == (Object)null)
					{
						throw new InvalidOperationException("Could not load visual shader bundle.");
					}
					try
					{
						peripheralShader = val.LoadAsset<Shader>("Assets/ExertionPeripheral.shader");
					}
					finally
					{
						val.Unload(false);
					}
				}
				if ((Object)(object)peripheralShader == (Object)null || !peripheralShader.isSupported)
				{
					throw new InvalidOperationException("Peripheral visual shader is unavailable or unsupported.");
				}
				material = new Material(peripheralShader)
				{
					hideFlags = (HideFlags)61
				};
				Status = "ready: masked radial blur + clarity";
			}
			catch (Exception ex)
			{
				Status = "FAILED: " + ex.Message;
				Debug.LogError((object)("Realistic Running visuals: " + Status));
			}
		}
		if (!((Object)(object)material == (Object)null))
		{
			material.SetFloat("_Intensity", sharedIntensity);
			material.SetFloat("_BlurStrength", blurStrength);
			material.SetFloat("_SharpenStrength", clarityStrength);
			material.SetFloat("_ClearRadius", clearRadius);
			material.SetFloat("_SaturationMultiplier", SaturationMultiplier);
		}
	}

	private void OnPreCull()
	{
		if (enableMotionAwareness)
		{
			motionAwareness.Prepare(((Component)this).GetComponent<Camera>());
		}
	}

	private void OnRenderImage(RenderTexture source, RenderTexture destination)
	{
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)material == (Object)null || intensity <= 1E-05f)
		{
			Graphics.Blit((Texture)(object)source, destination);
			return;
		}
		if (!enableMotionAwareness)
		{
			Graphics.Blit((Texture)(object)source, destination, material);
		}
		else
		{
			RenderTexture temporary = RenderTexture.GetTemporary(source.descriptor);
			try
			{
				Graphics.Blit((Texture)(object)source, temporary, material);
				if (!motionAwareness.Apply(((Component)this).GetComponent<Camera>(), source, temporary, destination, motionAwarenessStrength, motionClearRadius))
				{
					Graphics.Blit((Texture)(object)temporary, destination);
				}
			}
			finally
			{
				RenderTexture.ReleaseTemporary(temporary);
			}
		}
		RenderedFrames++;
	}

	private void OnDestroy()
	{
		motionAwareness.Dispose();
		if ((Object)(object)material != (Object)null)
		{
			Object.Destroy((Object)(object)material);
		}
	}

	private void OnDisable()
	{
		motionAwareness.Reset();
	}
}
internal enum MovementAudioPhase
{
	Silent,
	Start,
	Flow,
	Hill,
	Push,
	Adrenaline
}
internal sealed class MovementAudioSequencer
{
	private float stoppedSeconds;

	private float climbingSeconds;

	private float hillReleaseSeconds;

	private bool hillActive;

	public float RunSeconds { get; private set; }

	public MovementAudioPhase Phase { get; private set; }

	public void Reset()
	{
		float num = (RunSeconds = 0f);
		stoppedSeconds = (climbingSeconds = (hillReleaseSeconds = num));
		hillActive = false;
		Phase = MovementAudioPhase.Silent;
	}

	public MovementAudioPhase Step(bool running, bool climbing, MovementAudioPhase burst, float deltaSeconds, float startSeconds)
	{
		float num = Math.Max(0f, deltaSeconds);
		if (!running)
		{
			stoppedSeconds += num;
			if (stoppedSeconds >= 0.25f)
			{
				Reset();
			}
			return MovementAudioPhase.Silent;
		}
		stoppedSeconds = 0f;
		RunSeconds += num;
		bool flag = RunSeconds >= Math.Max(0.1f, startSeconds);
		if (!flag)
		{
			climbingSeconds = (hillReleaseSeconds = 0f);
			hillActive = false;
		}
		else if (climbing)
		{
			climbingSeconds += num;
			hillReleaseSeconds = 0f;
			if (climbingSeconds >= 0.75f)
			{
				hillActive = true;
			}
		}
		else
		{
			climbingSeconds = 0f;
			hillReleaseSeconds += num;
			if (hillReleaseSeconds >= 1.5f)
			{
				hillActive = false;
			}
		}
		if (burst == MovementAudioPhase.Push || burst == MovementAudioPhase.Adrenaline)
		{
			Phase = burst;
		}
		else
		{
			Phase = ((!flag) ? MovementAudioPhase.Start : (hillActive ? MovementAudioPhase.Hill : MovementAudioPhase.Flow));
		}
		return Phase;
	}
}
internal sealed class PeripheralMotionAwareness : IDisposable
{
	private Material material;

	private RenderTexture previousScene;

	private RenderTexture previousDepth;

	private Matrix4x4 previousViewProjection;

	private Vector3 previousPosition;

	private Quaternion previousRotation;

	private float previousFar;

	private float previousFov;

	private float previousTime;

	private bool historyValid;

	private bool failed;

	public string Status { get; private set; } = "disabled";

	public void Reset()
	{
		historyValid = false;
		Release(ref previousScene);
		Release(ref previousDepth);
		Status = (failed ? "unavailable; original rendering retained" : "disabled");
	}

	public void Prepare(Camera camera)
	{
		//IL_001c: 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)
		if ((Object)(object)camera != (Object)null && !failed)
		{
			camera.depthTextureMode = (DepthTextureMode)(camera.depthTextureMode | 1);
		}
	}

	public bool Apply(Camera camera, RenderTexture source, RenderTexture processed, RenderTexture destination, float strength, float clearRadius)
	{
		//IL_0178: Unknown result type (might be due to invalid IL or missing references)
		//IL_0149: 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_0231: Unknown result type (might be due to invalid IL or missing references)
		//IL_0237: Unknown result type (might be due to invalid IL or missing references)
		//IL_023d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0242: Unknown result type (might be due to invalid IL or missing references)
		//IL_0247: 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_02d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0195: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01de: 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_0391: 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_03ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_03bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0201: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: Expected O, but got Unknown
		if (failed || (Object)(object)camera == (Object)null || camera.orthographic)
		{
			return false;
		}
		try
		{
			if ((Object)(object)material == (Object)null)
			{
				using Stream stream = typeof(PeripheralMotionAwareness).Assembly.GetManifestResourceStream("RealisticRunning.exertionvisuals");
				using BinaryReader binaryReader = new BinaryReader(stream);
				AssetBundle val = AssetBundle.LoadFromMemory(binaryReader.ReadBytes((int)stream.Length));
				if ((Object)(object)val == (Object)null)
				{
					throw new InvalidOperationException("Motion-awareness bundle unavailable.");
				}
				Shader val2;
				try
				{
					val2 = val.LoadAsset<Shader>("Assets/PeripheralMotionAwareness.shader");
				}
				finally
				{
					val.Unload(false);
				}
				if ((Object)(object)val2 == (Object)null || !val2.isSupported)
				{
					throw new InvalidOperationException("Motion-awareness shader unsupported.");
				}
				material = new Material(val2)
				{
					hideFlags = (HideFlags)61
				};
			}
			if ((Object)(object)previousScene == (Object)null || ((Texture)previousScene).width != ((Texture)source).width || ((Texture)previousScene).height != ((Texture)source).height || previousScene.format != source.format)
			{
				Reset();
				previousScene = Create(((Texture)source).width, ((Texture)source).height, source.format);
				RenderTextureFormat format = (RenderTextureFormat)(SystemInfo.SupportsRenderTextureFormat((RenderTextureFormat)14) ? 14 : 2);
				previousDepth = Create(((Texture)source).width, ((Texture)source).height, format);
			}
			float unscaledTime = Time.unscaledTime;
			float num = unscaledTime - previousTime;
			bool flag = historyValid && num > 0f && num < 0.2f && Vector3.Distance(((Component)camera).transform.position, previousPosition) < 2f && Quaternion.Angle(((Component)camera).transform.rotation, previousRotation) < 20f && Mathf.Abs(camera.fieldOfView - previousFov) < 2f;
			Matrix4x4 val3 = GL.GetGPUProjectionMatrix(camera.projectionMatrix, false) * camera.worldToCameraMatrix;
			material.SetTexture("_SceneTex", (Texture)(object)source);
			material.SetVector("_SceneTex_TexelSize", new Vector4(1f / (float)((Texture)source).width, 1f / (float)((Texture)source).height, (float)((Texture)source).width, (float)((Texture)source).height));
			material.SetTexture("_PreviousScene", (Texture)(object)previousScene);
			material.SetTexture("_PreviousDepth", (Texture)(object)previousDepth);
			material.SetMatrix("_InverseViewProjection", ((Matrix4x4)(ref val3)).inverse);
			material.SetMatrix("_PreviousViewProjection", previousViewProjection);
			material.SetFloat("_PreviousFar", Mathf.Max(1f, previousFar));
			material.SetFloat("_FrameSeconds", num);
			material.SetFloat("_ClearRadius", clearRadius);
			material.SetFloat("_Strength", flag ? Mathf.Clamp01(strength) : 0f);
			Graphics.Blit((Texture)(object)processed, destination, material, 0);
			Graphics.Blit((Texture)(object)source, previousScene);
			Graphics.Blit((Texture)(object)source, previousDepth, material, 1);
			previousViewProjection = val3;
			previousFar = camera.farClipPlane;
			previousPosition = ((Component)camera).transform.position;
			previousRotation = ((Component)camera).transform.rotation;
			previousFov = camera.fieldOfView;
			previousTime = unscaledTime;
			historyValid = true;
			Status = (flag ? "camera-compensated motion contrast active" : "history reset (no enhancement)");
			return true;
		}
		catch (Exception)
		{
			failed = true;
			Dispose();
			Status = "unavailable; original rendering retained";
			return false;
		}
	}

	private static RenderTexture Create(int width, int height, RenderTextureFormat format)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: 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_0025: Expected O, but got Unknown
		RenderTexture val = new RenderTexture(width, height, 0, format, (RenderTextureReadWrite)1)
		{
			hideFlags = (HideFlags)61,
			filterMode = (FilterMode)1,
			wrapMode = (TextureWrapMode)1
		};
		if (!val.Create())
		{
			Object.Destroy((Object)(object)val);
			throw new InvalidOperationException("Motion history allocation failed.");
		}
		return val;
	}

	private static void Release(ref RenderTexture texture)
	{
		if ((Object)(object)texture != (Object)null)
		{
			texture.Release();
			Object.Destroy((Object)(object)texture);
		}
		texture = null;
	}

	public void Dispose()
	{
		Reset();
		if ((Object)(object)material != (Object)null)
		{
			Object.Destroy((Object)(object)material);
		}
		material = null;
	}
}
[BepInPlugin("com.marccunningham.survivalmovementexertion", "Realistic Running", "1.6.11")]
[BepInProcess("valheim.exe")]
public sealed class SurvivalMovementExertionPlugin : BaseUnityPlugin
{
	private enum PushState
	{
		Normal,
		Pushing,
		Adrenaline,
		RecoveryOne,
		RecoveryTwo
	}

	private sealed class LoopingAudioLayer
	{
		public AudioSource Source;

		public AudioClip Clip;

		public readonly AudioFadeEnvelope Fade = new AudioFadeEnvelope();

		public string Status = "not loaded";

		public string AssetPath = string.Empty;

		public float CurrentVolume => Fade.Value;
	}

	public const string PluginGuid = "com.marccunningham.survivalmovementexertion";

	public const string PluginName = "Realistic Running";

	public const string PluginVersion = "1.6.11";

	private const float MinimumInputMagnitude = 0.001f;

	private const float MinimumDuration = 0.01f;

	private const int TunnelTextureCount = 18;

	private const int TunnelTextureSize = 160;

	private const int DefaultWindStreakCount = 28;

	private const string ZdoPushState = "RealisticRunning_PushState";

	private const string ZdoPushStateRemaining = "RealisticRunning_PushStateRemaining";

	private const string ZdoPushMovementRecovery = "RealisticRunning_PushMovementRecovery";

	private const string ZdoPushMinimumRecoveryRemaining = "RealisticRunning_PushMinimumRecoveryRemaining";

	private const float ZdoMissingPushState = -1f;

	internal static SurvivalMovementExertionPlugin Instance;

	private ConfigEntry<bool> modEnabled;

	private ConfigEntry<KeyCode> diagnosticKey;

	private ConfigEntry<bool> showDiagnosticHud;

	private ConfigEntry<bool> enableDebugControls;

	private ConfigEntry<bool> enableVerboseLogging;

	private ConfigEntry<bool> enableInputSmoothing;

	private ConfigEntry<float> accelerationSeconds;

	private ConfigEntry<float> decelerationSeconds;

	private ConfigEntry<float> backwardSpeedMultiplier;

	private ConfigEntry<float> sidewaysSpeedMultiplier;

	private ConfigEntry<float> sprintBuildUpSeconds;

	private ConfigEntry<float> sprintStartSpeedFraction;

	private ConfigEntry<float> topSprintSpeedMultiplier;

	private ConfigEntry<float> sprintBuildRecoverySeconds;

	private ConfigEntry<float> baseRunStaminaDrainMultiplier;

	private ConfigEntry<float> maximumCombinedRunDrainMultiplier;

	private ConfigEntry<float> emergencySprintReleaseStaminaPercentage;

	private ConfigEntry<bool> enablePushStateMachine;

	private ConfigEntry<float> pushTapRatePerSecond;

	private ConfigEntry<float> pushTapSustainSeconds;

	private ConfigEntry<float> pushTapGraceSeconds;

	private ConfigEntry<float> adrenalineContinuousTapSeconds;

	private ConfigEntry<float> pushSpeedMultiplier;

	private ConfigEntry<float> adrenalineSpeedMultiplier;

	private ConfigEntry<float> adrenalineStaminaDrainMultiplier;

	private ConfigEntry<float> adrenalineOnsetSeconds;

	private ConfigEntry<float> adrenalineOnsetFov;

	private ConfigEntry<float> adrenalineCombatRange;

	private ConfigEntry<float> adrenalineFacingDotThreshold;

	private ConfigEntry<float> adrenalineHeartbeatBaselineBpm;

	private ConfigEntry<float> adrenalineCombatHeartbeatMultiplier;

	private ConfigEntry<float> adrenalineCombatDecayNearSeconds;

	private ConfigEntry<float> adrenalineCombatDecayFarSeconds;

	private ConfigEntry<float> pushStaminaDrainMultiplier;

	private ConfigEntry<float> eTapNativeStaminaCost;

	private ConfigEntry<float> recoveryOneJogCapSeconds;

	private ConfigEntry<float> recoveryOneBreathingTaperSeconds;

	private ConfigEntry<float> recoveryTwoWalkOnlySeconds;

	private ConfigEntry<float> flatSlopeDrainBonus;

	private ConfigEntry<float> exertionGainPerSecond;

	private ConfigEntry<float> exertionRecoveryPerSecond;

	private ConfigEntry<float> stationaryRecoveryMultiplier;

	private ConfigEntry<float> highExertionStart;

	private ConfigEntry<float> highExertionRunSpeedMultiplier;

	private ConfigEntry<float> highExertionDrainMultiplier;

	private ConfigEntry<float> exhaustionTriggerStaminaPercentage;

	private ConfigEntry<float> exhaustedJogSeconds;

	private ConfigEntry<float> exhaustedJogSpeedMultiplier;

	private ConfigEntry<float> recoveryStaminaPercentage;

	private ConfigEntry<float> recoveryExertionPercentage;

	private ConfigEntry<bool> enableHillEffects;

	private ConfigEntry<float> hillGraceAngle;

	private ConfigEntry<float> hillFullPenaltyAngle;

	private ConfigEntry<float> uphillSpeedPenalty;

	private ConfigEntry<float> uphillDrainMultiplier;

	private ConfigEntry<float> uphillExertionMultiplier;

	private ConfigEntry<float> downhillSpeedBonus;

	private ConfigEntry<float> downhillDrainReduction;

	private ConfigEntry<bool> enableWeatherEffects;

	private ConfigEntry<float> wetSpeedMultiplier;

	private ConfigEntry<float> wetDrainMultiplier;

	private ConfigEntry<float> wetExertionMultiplier;

	private ConfigEntry<float> coldDrainMultiplier;

	private ConfigEntry<float> coldExertionMultiplier;

	private ConfigEntry<float> freezingSpeedMultiplier;

	private ConfigEntry<float> freezingDrainMultiplier;

	private ConfigEntry<float> freezingExertionMultiplier;

	private ConfigEntry<bool> enableInjuryCompatibility;

	private ConfigEntry<float> injuryExertionPenaltyStrength;

	private ConfigEntry<bool> applyInjurySpeedCompatibilityPenalty;

	private ConfigEntry<float> factorRefreshSeconds;

	private ConfigEntry<bool> enableTunnelVision;

	private ConfigEntry<float> tunnelVisionStartExertion;

	private ConfigEntry<float> tunnelVisionFullExertion;

	private ConfigEntry<float> maximumTunnelVisionAlpha;

	private ConfigEntry<float> tunnelVisionPulseStrength;

	private ConfigEntry<float> tunnelVisionClearRadiusAtExhaustion;

	private ConfigEntry<bool> enableWindRushStreaks;

	private ConfigEntry<int> windRushStreakCount;

	private ConfigEntry<float> windRushStartSprintBuild;

	private ConfigEntry<float> windRushMaximumAlpha;

	private ConfigEntry<float> windRushTravelSpeed;

	private ConfigEntry<bool> enableCameraSway;

	private ConfigEntry<bool> cameraSwayClosestZoomOnly;

	private ConfigEntry<float> closestZoomTolerance;

	private ConfigEntry<float> sprintBobVerticalMeters;

	private ConfigEntry<float> sprintBobSideMeters;

	private ConfigEntry<float> fatigueBreathSwayMeters;

	private ConfigEntry<float> sprintSwayFrequencyLow;

	private ConfigEntry<float> sprintSwayFrequencyHigh;

	private ConfigEntry<float> breathSwayFrequencyLow;

	private ConfigEntry<float> breathSwayFrequencyHigh;

	private ConfigEntry<float> cameraSwaySmoothingSeconds;

	private ConfigEntry<float> coolEdgeTintStrength;

	private ConfigEntry<bool> enableNativeDepthOfField;

	private ConfigEntry<bool> depthOfFieldClosestZoomOnly;

	private ConfigEntry<float> depthOfFieldStartVisualIntensity;

	private ConfigEntry<float> depthOfFieldMaximumBlurSize;

	private ConfigEntry<float> depthOfFieldFocalSizeAtExhaustion;

	private ConfigEntry<float> depthOfFieldFallbackFocusDistance;

	private ConfigEntry<float> depthOfFieldMaximumFocusDistance;

	private ConfigEntry<float> flowStateBaseFov;

	private ConfigEntry<float> flowStateMaximumFov;

	private ConfigEntry<float> pushStateFov;

	private ConfigEntry<float> adrenalineStateFov;

	private ConfigEntry<float> visualTierTransitionSeconds;

	private ConfigEntry<float> adrenalineAudioFadeSeconds;

	private ConfigEntry<float> exertionVisualTimeConstantSeconds;

	private ConfigEntry<bool> enableControlledMotionBlur;

	private ConfigEntry<bool> enableFlowColorSaturation;

	private ConfigEntry<float> flowSaturationMultiplier;

	private ConfigEntry<bool> enableFlowClarity;

	private ConfigEntry<float> flowClarityStrength;

	private ConfigEntry<float> peripheralMotionBlurStrength;

	private ConfigEntry<bool> enablePeripheralMotionAwareness;

	private ConfigEntry<float> peripheralMotionAwarenessStrength;

	private ConfigEntry<bool> enablePeripheralBlurOverlay;

	private ConfigEntry<float> peripheralBlurStartIntensity;

	private ConfigEntry<float> peripheralBlurMaximumAlpha;

	private ConfigEntry<float> peripheralBlurClearRadiusAtExhaustion;

	private ConfigEntry<bool> enableExhaustionHeartbeat;

	private ConfigEntry<float> heartbeatStartPressure;

	private ConfigEntry<float> heartbeatRecoveryBpm;

	private ConfigEntry<float> heartbeatMaximumBpm;

	private ConfigEntry<float> heartbeatMaximumVolume;

	private ConfigEntry<float> heartbeatIntensitySmoothingSeconds;

	private ConfigEntry<bool> enableMovementAudio;

	private ConfigEntry<float> shallowBreathVolume;

	private ConfigEntry<float> flowBreathVolume;

	private ConfigEntry<float> heavyBreathVolume;

	private ConfigEntry<float> stompFootstepVolume;

	private ConfigEntry<float> runStartAudioSeconds;

	private ConfigEntry<float> movementAudioCrossfadeSeconds;

	private ConfigEntry<bool> enableBaselineExhaustionBreathing;

	private ConfigEntry<float> exhaustionBreathRestRecoverySeconds;

	private ConfigEntry<float> exhaustionBreathJogRecoverySeconds;

	private ConfigEntry<float> exhaustionBreathInitialVolume;

	private ConfigEntry<float> exhaustionBreathInitialPitch;

	private ConfigEntry<bool> showRecoverySeconds;

	private Harmony harmony;

	private bool setControlsPatchInstalled;

	private bool jogSpeedPatchInstalled;

	private bool runSpeedPatchInstalled;

	private bool checkRunPatchInstalled;

	private bool recoveryWalkingPatchInstalled;

	private bool lastSprintInputRequested;

	private Player visualInputPlayer;

	private bool visualRawMovementRequested;

	private bool visualSprintRequested;

	private bool cameraPositionPatchInstalled;

	private bool cameraFovPatchInstalled;

	private bool cameraFovSourcePatchInstalled;

	private bool cameraFovLatePatchInstalled;

	private GameCamera ownedFovManager;

	private bool nativeFovClaimed;

	private float nativeFovBeforeClaim;

	private float nativeFovTargetBeforeClaim;

	private Camera gameplayCamera;

	private int cameraFovHookCalls;

	private float lastAppliedFov = 60f;

	private bool depthOfFieldPatchInstalled;

	private int setControlsHookCalls;

	private int jogSpeedHookCalls;

	private int runSpeedHookCalls;

	private int checkRunHookCalls;

	private int cameraHookCalls;

	private int depthOfFieldHookCalls;

	private float smoothedInputMagnitude;

	private float sprintBuild;

	private float exertion;

	private float exhaustedJogRemaining;

	private bool fatigueRecoveryActive;

	private bool baselineMovementRecoveryActive;

	private bool wasSprinting;

	private bool baselineExhaustionBreathingActive;

	private bool baselineExhaustionBreathingCompleted;

	private float baselineExhaustionBreathingProgress;

	private bool baselineSprintAttemptWasHeld;

	private float baselineExhaustionNextGaspTime;

	private string baselineExhaustionBreathingStatus = "idle";

	private float lastRunDrainMultiplier = 1f;

	private float factorRefreshTimer = 999f;

	private PushState pushState;

	private float pushStateRemaining;

	private bool pushMovementRecoveryActive;

	private float pushMinimumRecoveryRemaining;

	private float lastObservedStaminaForAdrenalineRefund = -1f;

	private float adrenalineRefundTotalDrop;

	private float adrenalineRefundTotalRefunded;

	private float adrenalineRefundNextLogTime;

	private readonly Queue<float> tapTimes = new Queue<float>();

	private float fastTapStartedAt = -1f;

	private float lastFastTapSatisfiedTime = -1f;

	private bool cachedClimbingSlope;

	private bool pushStateLoaded;

	private float pushStateSaveTimer;

	private float adrenalineFovOverride = -1f;

	private float adrenalineCombatSpike;

	private float adrenalineCombatLostAt = -1f;

	private float adrenalineLastEnemyDistance = float.MaxValue;

	private bool adrenalineOnsetAudioMuted;

	private float audioListenerVolumeBeforeAdrenalineMute = 1f;

	private float adrenalineAudioDuckBlend;

	private MethodInfo getAllCharactersMethod;

	private MethodInfo isMonsterFactionMethod;

	private float terrainSpeedMultiplier = 1f;

	private float terrainDrainMultiplier = 1f;

	private float terrainExertionMultiplier = 1f;

	private float weatherSpeedMultiplier = 1f;

	private float weatherDrainMultiplier = 1f;

	private float weatherExertionMultiplier = 1f;

	private float weatherRecoveryMultiplier = 1f;

	private float injurySpeedMultiplier = 1f;

	private float injuryExertionMultiplier = 1f;

	private float cachedSlopeAngle;

	private bool cachedWet;

	private bool cachedCold;

	private bool cachedFreezing;

	private float smoothedCameraSwayVertical;

	private float smoothedCameraSwaySide;

	private float cameraSwayVerticalVelocity;

	private float cameraSwaySideVelocity;

	private float latestCameraDistance = float.MaxValue;

	private float latestCameraMinimumDistance = float.MaxValue;

	private float smoothedExertionVisual;

	private float targetExertionVisual;

	private float visualTransitionFromTier;

	private float visualTransitionToTier = -1f;

	private float visualTransitionElapsed;

	private ExertionVisualRenderer exertionVisualRenderer;

	private const float WindRushClearRadius = 0.42f;

	private Component heartbeatAudioSource;

	private Object heartbeatClip;

	private MethodInfo heartbeatPlayOneShotMethod;

	private MethodInfo heartbeatStopMethod;

	private bool audioPausedByMenu;

	private float heartbeatNextBeatTime;

	private float heartbeatCurrentPressure;

	private float heartbeatPressureVelocity;

	private float heartbeatCurrentBpm;

	private string heartbeatStatus = "not loaded";

	private string heartbeatAssetPath = string.Empty;

	private LoopingAudioLayer shallowBreathLayer;

	private LoopingAudioLayer flowBreathLayer;

	private LoopingAudioLayer heavyBreathLayer;

	private LoopingAudioLayer stompFootstepLayer;

	private readonly MovementAudioSequencer movementAudioSequence = new MovementAudioSequencer();

	private string lastMovementAudioSelection = string.Empty;

	private bool audioDebugMuted;

	private int audioSoloPreview;

	private FieldInfo cameraEffectsDofField;

	private FieldInfo cameraEffectsDofRayMaskField;

	private FieldInfo cameraEffectsMotionBlurField;

	private MemberInfo postProcessingProfileMember;

	private MemberInfo postProcessingMotionBlurMember;

	private MemberInfo dofFocusDistanceMember;

	private MemberInfo dofFocalSizeMember;

	private MemberInfo dofMaxBlurSizeMember;

	private MemberInfo dofApertureMember;

	private bool depthOfFieldReflectionReady;

	private bool depthOfFieldAvailable;

	private string depthOfFieldStatus = "not resolved";

	private MemberInfo motionBlurEnabledMember;

	private bool motionBlurReflectionReady;

	private bool motionBlurAvailable;

	private string motionBlurStatus = "not resolved";

	private string flowColorStatus = "not resolved";

	private Type injuryPluginType;

	private FieldInfo injuryInstanceField;

	private MethodInfo injuryIsActiveForMethod;

	private MethodInfo injuryRunSpeedMultiplierMethod;

	private bool injuryReflectionUsable;

	private FieldInfo survivalViewExternalFovAuthorityField;

	private FieldInfo survivalViewExternalMovementAuthorityField;

	private Delegate survivalViewAuthorityDelegate;

	private bool survivalViewAuthorityClaimed;

	private Texture2D[] tunnelTextures;

	private Texture2D[] peripheralBlurTextures;

	private WindStreak[] windStreaks;

	private GUIStyle diagnosticStyle;

	private FieldInfo hudInstanceField;

	private FieldInfo hudStaminaBarRootField;

	private MethodInfo hudIsVisibleMethod;

	private bool nativeStaminaBarHiddenByUs;

	private ConfigEntry<bool> enableBloodPulse;

	private ConfigEntry<float> bloodPulseMinVolume;

	private ConfigEntry<float> bloodPulseMaxVolume;

	private ConfigEntry<float> bloodPulseVignetteMaxAlpha;

	private Component bloodPulseAudioSource;

	private Object bloodPulseClip;

	private string bloodPulseStatus = "not loaded";

	private string bloodPulseAssetPath = string.Empty;

	private float bloodPulseVignetteAlpha;

	private float lastHeartbeatBeatTime = -999f;

	private float lastHeartbeatBeatVolume = 1f;

	private Texture2D bloodPulseVignetteTexture;

	private void Awake()
	{
		Instance = this;
		BindConfig();
		TryClaimSurvivalViewAuthority();
		MigratePerceptibilityDefaults();
		MigrateEscapeSafetyDefaults();
		MigratePushStateDefaults();
		MigrateFlowFovDefaults();
		MigrateMovementAudioDefaults();
		InstallPatches();
		TryLoadHeartbeatAudio();
		TryLoadBloodPulseAudio();
		TryLoadMovementAudio();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Realistic Running 1.6.11 loaded.");
	}

	private void LogVerbose(string message)
	{
		if (enableVerboseLogging != null && enableVerboseLogging.Value)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)message);
		}
	}

	private void OnDestroy()
	{
		RestoreNativeFovOwnership();
		if ((Object)(object)exertionVisualRenderer != (Object)null)
		{
			Object.Destroy((Object)(object)exertionVisualRenderer);
		}
		TrySavePushState();
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
		ReleaseSurvivalViewAuthority();
		EndAdrenalineOnsetAudioMute(immediate: true);
		ApplyNativeStaminaBarVisibility(visible: true);
		StopHeartbeatAudio();
		StopBloodPulseAudio();
		DestroyMovementAudio();
		if ((Object)(object)heartbeatAudioSource != (Object)null)
		{
			Object.Destroy((Object)(object)heartbeatAudioSource);
			heartbeatAudioSource = null;
		}
		if (heartbeatClip != (Object)null)
		{
			Object.Destroy(heartbeatClip);
			heartbeatClip = null;
		}
		if ((Object)(object)bloodPulseAudioSource != (Object)null)
		{
			Object.Destroy((Object)(object)bloodPulseAudioSource);
			bloodPulseAudioSource = null;
		}
		if (bloodPulseClip != (Object)null)
		{
			Object.Destroy(bloodPulseClip);
			bloodPulseClip = null;
		}
		if ((Object)(object)bloodPulseVignetteTexture != (Object)null)
		{
			Object.Destroy((Object)(object)bloodPulseVignetteTexture);
			bloodPulseVignetteTexture = null;
		}
		DestroyTunnelTextures();
		DestroyPeripheralBlurTextures();
		windStreaks = null;
		if ((Object)(object)Instance == (Object)(object)this)
		{
			Instance = null;
		}
	}

	private void Update()
	{
		//IL_0295: Unknown result type (might be due to invalid IL or missing references)
		if (IsGamePaused())
		{
			StopMovementAudio();
			StopHeartbeatAudio();
			StopBloodPulseAudio();
			StopAllRecognizedRunningAudio();
			EndAdrenalineOnsetAudioMute();
			bloodPulseVignetteAlpha = 0f;
			audioPausedByMenu = true;
			return;
		}
		if (audioPausedByMenu)
		{
			audioPausedByMenu = false;
			heartbeatNextBeatTime = Time.unscaledTime + 0.1f;
			baselineExhaustionNextGaspTime = Time.time;
			baselineSprintAttemptWasHeld = lastSprintInputRequested;
		}
		if (enableDebugControls.Value)
		{
			if (Input.GetKeyDown((KeyCode)288))
			{
				Player localPlayer = Player.m_localPlayer;
				if (IsMovementEligible(localPlayer) && enablePushStateMachine.Value)
				{
					pushState = PushState.Adrenaline;
					pushStateRemaining = 210f;
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Realistic Running: F7 debug-forced entry into Adrenaline. stamina=" + localPlayer.GetStamina().ToString("0.00") + "/" + ((Character)localPlayer).GetMaxStamina().ToString("0.00")));
				}
			}
			if (Input.GetKeyDown((KeyCode)291))
			{
				audioSoloPreview = (audioSoloPreview + 1) % 5;
				StopMovementAudio();
				StopHeartbeatAudio();
				StopBloodPulseAudio();
				StopAllRecognizedRunningAudio();
				movementAudioSequence.Reset();
				lastMovementAudioSelection = string.Empty;
				audioDebugMuted = false;
				if ((Object)(object)heartbeatAudioSource != (Object)null)
				{
					SetNumericProperty(((object)heartbeatAudioSource).GetType(), heartbeatAudioSource, "volume", 1f);
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Realistic Running: F10 solo preview=" + GetAudioSoloPreviewName() + ". Previews play without running; all other RR audio is stopped."));
			}
			if (Input.GetKeyDown((KeyCode)290))
			{
				audioDebugMuted = !audioDebugMuted;
				if (audioDebugMuted)
				{
					StopMovementAudio();
					StopHeartbeatAudio();
					StopBloodPulseAudio();
					StopAllRecognizedRunningAudio();
				}
				else if ((Object)(object)heartbeatAudioSource != (Object)null)
				{
					SetNumericProperty(((object)heartbeatAudioSource).GetType(), heartbeatAudioSource, "volume", 1f);
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Realistic Running: F9 audio mute=" + audioDebugMuted + ". F8 prints all audible Unity sources."));
				WriteLiveAudioAudit();
			}
			if (Input.GetKeyDown(diagnosticKey.Value))
			{
				WriteDiagnostic();
			}
		}
		if (audioSoloPreview != 0)
		{
			UpdateAudioSoloPreview();
		}
		Player localPlayer2 = Player.m_localPlayer;
		if (!IsMovementEligible(localPlayer2))
		{
			lastObservedStaminaForAdrenalineRefund = -1f;
			EndAdrenalineOnsetAudioMute((Object)(object)localPlayer2 == (Object)null || ((Character)localPlayer2).IsDead());
			ResetTransientMovementState();
			UpdateExertionVisual(localPlayer2);
			return;
		}
		EnsurePushStateLoaded(localPlayer2);
		RecordTapInput(localPlayer2);
		ApplyPushTierStaminaRefund(localPlayer2);
		UpdatePushState(localPlayer2);
		UpdatePushMovementRecovery(localPlayer2, Time.deltaTime);
		SavePushStateIfDue(localPlayer2);
		factorRefreshTimer += Time.deltaTime;
		if (factorRefreshTimer >= Mathf.Max(0.05f, factorRefreshSeconds.Value))
		{
			factorRefreshTimer = 0f;
			RefreshWorldFactors(localPlayer2);
			TryClaimSurvivalViewAuthority();
		}
		UpdateExertion(localPlayer2);
		UpdateAdrenalineSensory(localPlayer2);
		UpdateExertionVisual(localPlayer2);
		UpdateVisualMotion(localPlayer2);
		UpdateHeartbeatAudio(localPlayer2);
		UpdateMovementAudio(localPlayer2);
		UpdateBaselineExhaustionBreathing(localPlayer2);
	}

	private void OnGUI()
	{
		Player localPlayer = Player.m_localPlayer;
		if (!((Object)(object)localPlayer == (Object)null) && modEnabled.Value)
		{
			DrawWindRush(localPlayer);
			DrawPeripheralBlur(localPlayer);
			DrawTunnelVision(localPlayer);
			DrawBloodPulseVignette();
			DrawRecoveryStatus(localPlayer);
			DrawDiagnosticHud(localPlayer);
		}
	}

	private void BindConfig()
	{
		//IL_0ba1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0bc4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0bce: Expected O, but got Unknown
		//IL_0bce: Expected O, but got Unknown
		modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Turns Realistic Running on or off without removing the DLL.");
		diagnosticKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Debug", "DiagnosticKey", (KeyCode)289, "Diagnostic key used only while EnableDebugControls is true.");
		enableDebugControls = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableDebugControls", false, "Enables test-only F7/F8/F9/F10 controls. Leave disabled during normal play.");
		enableVerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableVerboseLogging", false, "Writes detailed audio transitions, state changes and stamina accounting to BepInEx/LogOutput.log. Leave disabled during normal play.");
		showDiagnosticHud = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "ShowDiagnosticHud", false, "Shows a small top-left exertion readout for balancing. Leave off for normal play.");
		enableInputSmoothing = ((BaseUnityPlugin)this).Config.Bind<bool>("Movement", "EnableInputSmoothing", true, "Smooths input magnitude while preserving immediate turning direction. This creates acceleration and deceleration without steering lag.");
		accelerationSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "AccelerationSeconds", 0.28f, "Seconds for a stationary player to build toward full movement input. Higher values feel heavier.");
		decelerationSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "DecelerationSeconds", 0.18f, "Seconds for movement input to settle after keys are released. Higher values feel less abrupt.");
		backwardSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "BackwardSpeedMultiplier", 0.7f, "Speed while moving directly backward. Diagonal movement blends naturally between forward, sideways and backward values.");
		sidewaysSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "SidewaysSpeedMultiplier", 0.86f, "Speed while moving directly sideways.");
		sprintBuildUpSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Sprint", "SprintBuildUpSeconds", 1.35f, "Seconds for sprinting to build from the initial run into maximum speed.");
		sprintStartSpeedFraction = ((BaseUnityPlugin)this).Config.Bind<float>("Sprint", "SprintStartSpeedFraction", 0.72f, "Fraction of top sprint speed available the instant sprinting begins. It rises to full TopSprintSpeedMultiplier over SprintBuildUpSeconds. V1.1.1 starts close to normal run speed, then visibly builds into a faster sprint.");
		topSprintSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Sprint", "TopSprintSpeedMultiplier", 1.45f, "Maximum healthy forward sprint multiplier relative to Valheim's native running speed. V1.1.4 gives a clearly faster full sprint while retaining build-up, exertion and recovery.");
		sprintBuildRecoverySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Sprint", "SprintBuildRecoverySeconds", 0.6f, "Seconds for sprint build-up to fade after the player stops running.");
		baseRunStaminaDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Sprint", "BaseRunStaminaDrainMultiplier", 0.15f, "Multiplier applied to Valheim's native run stamina drain. 0.15 aims for roughly 45-60 seconds of healthy sustained running with the same stamina pool, before terrain and exertion are considered.");
		maximumCombinedRunDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Safety", "MaximumCombinedRunDrainMultiplier", 2.25f, "Safety cap for all combined run-drain effects from exertion, terrain, weather and compatible survival mods. It keeps a bad situation difficult without making every sprint attempt instantly empty the bar.");
		emergencySprintReleaseStaminaPercentage = ((BaseUnityPlugin)this).Config.Bind<float>("Safety", "EmergencySprintReleaseStaminaPercentage", 0.22f, "After the minimum exhausted-jog time ends, sprinting is allowed again once stamina reaches this fraction even while exertion recovery continues. This prevents a long no-sprint lock while keeping escape costly.");
		enablePushStateMachine = ((BaseUnityPlugin)this).Config.Bind<bool>("Push State Machine", "Enabled", true, "Enables tap-driven Pushing, Adrenaline and fixed recovery states.");
		pushTapRatePerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "TapRatePerSecond", 3f, "E-key taps per second required to begin Pushing. Tune after playtesting. 4/sec proved too hard to sustain continuously for real players in practice.");
		pushTapSustainSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "TapSustainSeconds", 1.5f, "Continuous fast-tap duration required to enter Pushing.");
		pushTapGraceSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "TapGraceSeconds", 0.5f, "How long the fast-tap state survives after the per-second tap count last held. Absorbs single frame hitches (terrain loads, hard landings) that would otherwise expire several taps at once and eject the player from Pushing/Adrenaline build-up.");
		adrenalineContinuousTapSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "AdrenalineContinuousTapSeconds", 13.5f, "Continuous fast-tap duration from Pushing before Adrenaline begins.");
		pushSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "PushSpeedMultiplier", 1f, "Multiplier relative to normal sprint speed while Pushing. Minimum 1.0: tapping E must never slow normal sprinting. Adrenaline uses its separate multiplier.");
		adrenalineSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "AdrenalineSpeedMultiplier", 1.1f, "Final movement multiplier while Adrenaline is active.");
		adrenalineStaminaDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "AdrenalineStaminaDrainMultiplier", 0.5f, "Multiplier applied to Valheim's native sprint stamina drain for the full Adrenaline duration. 0.5 doubles effective stamina range.");
		eTapNativeStaminaCost = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "ETapNativeStaminaCost", 0.05f, "Extra native stamina points spent per accepted E tap while running. Recovery starts only when native stamina is zero.");
		adrenalineOnsetSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Adrenaline Sensory", "OnsetSeconds", 5f, "Duration of onset audio focus: game audio fades down by 70% and heartbeat_double.wav fades up to full volume. FOV follows the normal Adrenaline tier.");
		adrenalineOnsetFov = ((BaseUnityPlugin)this).Config.Bind<float>("Adrenaline Sensory", "OnsetFov", 45f, "Sharp tunnel FOV used during Adrenaline onset and when an enemy encounter fully re-tightens the tunnel.");
		adrenalineCombatRange = ((BaseUnityPlugin)this).Config.Bind<float>("Adrenaline Sensory", "CombatRange", 30f, "Maximum distance at which a faced monster counts as an Adrenaline combat encounter.");
		adrenalineFacingDotThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Adrenaline Sensory", "FacingDotThreshold", 0.35f, "Minimum forward-dot value required for a nearby monster to count as faced/engaged. 0.35 is roughly a 70 degree forward cone.");
		adrenalineHeartbeatBaselineBpm = ((BaseUnityPlugin)this).Config.Bind<float>("Adrenaline Sensory", "HeartbeatBaselineBPM", 124f, "Elevated baseline heartbeat throughout Adrenaline sustained phase.");
		adrenalineCombatHeartbeatMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Adrenaline Sensory", "CombatHeartbeatMultiplier", 1.25f, "Heartbeat multiplier during a faced combat encounter. 1.25 is the specified +25% spike.");
		adrenalineCombatDecayNearSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Adrenaline Sensory", "CombatDecayNearSeconds", 8f, "Slow-start then accelerating decay time after losing a nearby enemy encounter.");
		adrenalineCombatDecayFarSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Adrenaline Sensory", "CombatDecayFarSeconds", 2.5f, "Faster decay time once clear of nearby enemies.");
		pushStaminaDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "PushStaminaDrainMultiplier", 1f, "Normal native sprint drain while Pushing, plus ETapNativeStaminaCost per accepted E tap. Adrenaline has its separate drain multiplier.");
		if (Mathf.Abs(pushStaminaDrainMultiplier.Value - 0.5f) < 0.0001f)
		{
			pushStaminaDrainMultiplier.Value = 1f;
		}
		recoveryOneJogCapSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "RecoveryOneJogCapSeconds", 50f, "First phase of Pushing recovery. Walking/jogging allowed; sprint/push remain locked until all of Recovery One finishes.");
		recoveryOneBreathingTaperSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "RecoveryOneBreathingTaperSeconds", 30f, "Final breathing taper phase of Recovery One; sprint/push stay locked until this phase also completes.");
		recoveryTwoWalkOnlySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "RecoveryTwoWalkOnlySeconds", 120f, "Adrenaline burnout duration during which jogging, sprinting and pushing are locked.");
		flatSlopeDrainBonus = ((BaseUnityPlugin)this).Config.Bind<float>("Terrain", "FlatSlopeDrainBonus", 0.0135f, "Flat stamina-drain bonus on any slope, replacing the previous angle-scaled slope drain.");
		exertionGainPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Exertion", "SprintExertionGainPerSecond", 1.5f, "Exertion gained per second while sprinting on neutral ground. A long hard run approaches high exertion.");
		exertionRecoveryPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Exertion", "RecoveryPerSecond", 2.5f, "Exertion removed per second while walking or resting. Recovery is intentionally slower than the old version so hard running has a believable after-effect.");
		stationaryRecoveryMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Exertion", "StationaryRecoveryMultiplier", 1.75f, "Extra exertion recovery while standing still. Resting should recover you faster than walking onward.");
		highExertionStart = ((BaseUnityPlugin)this).Config.Bind<float>("Exertion", "HighExertionStart", 35f, "Exertion percentage where heavy breathing, tunnel vision and late-run penalties begin building. V1.1.1 starts the feedback earlier so the player can feel effort building before complete exhaustion.");
		highExertionRunSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Exertion", "HighExertionRunSpeedMultiplier", 0.84f, "Minimum late-run speed multiplier at 100 exertion. Exhaustion should feel heavy, not like walking through glue.");
		highExertionDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Exertion", "HighExertionDrainMultiplier", 1.9f, "Additional stamina-drain multiplier reached at maximum exertion. Sustained hard running becomes less efficient instead of ending abruptly.");
		exhaustionTriggerStaminaPercentage = ((BaseUnityPlugin)this).Config.Bind<float>("Fatigue Recovery", "ExhaustionTriggerStaminaPercentage", 0.08f, "Stamina percentage threshold used after native stamina reaches zero. Remaining stamina never starts a recovery movement lock.");
		exhaustedJogSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Fatigue Recovery", "MinimumExhaustedJogSeconds", 5.5f, "Minimum number of seconds the player remains in a hard-jog recovery state after sprinting to near-zero stamina.");
		exhaustedJogSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Fatigue Recovery", "ExhaustedJogSpeedMultiplier", 0.88f, "Jog-speed multiplier during hard fatigue recovery.");
		recoveryStaminaPercentage = ((BaseUnityPlugin)this).Config.Bind<float>("Fatigue Recovery", "RecoveryStaminaPercentage", 0.28f, "Stamina percentage required before hard fatigue can end.");
		recoveryExertionPercentage = ((BaseUnityPlugin)this).Config.Bind<float>("Fatigue Recovery", "RecoveryExertionPercentage", 55f, "Exertion percentage required before hard fatigue can end. This gives exhaustion a believable recovery period after a long run.");
		enableHillEffects = ((BaseUnityPlugin)this).Config.Bind<bool>("Terrain", "EnableHillEffects", true, "Applies uphill and downhill movement/exertion effects using Valheim's real ground normal.");
		hillGraceAngle = ((BaseUnityPlugin)this).Config.Bind<float>("Terrain", "HillGraceAngle", 7f, "Slope angle in degrees before hill effects begin.");
		hillFullPenaltyAngle = ((BaseUnityPlugin)this).Config.Bind<float>("Terrain", "HillFullPenaltyAngle", 35f, "Slope angle in degrees where maximum hill effects apply.");
		uphillSpeedPenalty = ((BaseUnityPlugin)this).Config.Bind<float>("Terrain", "MaxUphillSpeedPenalty", 0.22f, "Maximum speed reduction while moving directly uphill on a steep slope.");
		uphillDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Terrain", "MaxUphillDrainMultiplier", 1.5f, "Maximum extra run stamina drain while moving directly uphill on a steep slope.");
		uphillExertionMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Terrain", "MaxUphillExertionMultiplier", 1.65f, "Maximum extra exertion build while moving directly uphill on a steep slope.");
		downhillSpeedBonus = ((BaseUnityPlugin)this).Config.Bind<float>("Terrain", "MaxDownhillSpeedBonus", 0.04f, "Maximum small speed bonus while moving directly downhill. Kept low to avoid unsafe runaway movement.");
		downhillDrainReduction = ((BaseUnityPlugin)this).Config.Bind<float>("Terrain", "MaxDownhillDrainReduction", 0.12f, "Maximum reduction in sprint stamina drain while moving directly downhill.");
		enableWeatherEffects = ((BaseUnityPlugin)this).Config.Bind<bool>("Weather", "EnableWeatherEffects", true, "Applies realistic movement and exertion effects for wet, cold and freezing conditions.");
		wetSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Weather", "WetSpeedMultiplier", 0.97f, "Movement multiplier while wet. Kept mild: wetness should make travel harder without feeling sticky.");
		wetDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Weather", "WetRunDrainMultiplier", 1.14f, "Sprint stamina-drain multiplier while wet.");
		wetExertionMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Weather", "WetExertionMultiplier", 1.16f, "Exertion-gain multiplier while wet.");
		coldDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Weather", "ColdRunDrainMultiplier", 1.08f, "Sprint stamina-drain multiplier in cold weather.");
		coldExertionMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Weather", "ColdExertionMultiplier", 1.1f, "Exertion-gain multiplier in cold weather.");
		freezingSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Weather", "FreezingSpeedMultiplier", 0.95f, "Movement multiplier in freezing conditions.");
		freezingDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Weather", "FreezingRunDrainMultiplier", 1.25f, "Sprint stamina-drain multiplier in freezing conditions.");
		freezingExertionMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Weather", "FreezingExertionMultiplier", 1.28f, "Exertion-gain multiplier in freezing conditions.");
		enableInjuryCompatibility = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "EnableYoureInjuredCompatibility", true, "Reads the installed You're Injured mod through safe reflection. It makes leg injuries build exertion faster and can apply its leg-speed penalty to Player overrides in current Valheim builds.");
		injuryExertionPenaltyStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Compatibility", "InjuryExertionPenaltyStrength", 0.85f, "How strongly leg injuries increase exertion. 0 disables the extra exertion link while preserving any direct injury speed effect.");
		applyInjurySpeedCompatibilityPenalty = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "ApplyYoureInjuredSpeedCompatibilityPenalty", true, "Applies the existing You're Injured leg-speed multiplier to Player movement. Leave true for current builds where the original injury speed patch targets Character instead of Player. Turn off only if a later You're Injured update already patches Player speed directly.");
		factorRefreshSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Compatibility", "FactorRefreshSeconds", 0.15f, "How often terrain, weather and optional-mod factors are refreshed. Lower values react faster; defaults are light on performance.");
		enableTunnelVision = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnableExhaustionTunnelVision", true, "Narrows peripheral vision progressively during sustained sprinting. The effect begins mild, then tightens and pulses more strongly as exertion builds toward exhaustion.");
		tunnelVisionStartExertion = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "TunnelVisionStartExertion", 8f, "Exertion percentage where a faint peripheral narrowing begins during a sustained run. The effect then builds continuously instead of appearing only at complete exhaustion.");
		tunnelVisionFullExertion = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "TunnelVisionFullExertion", 88f, "Exertion percentage where the tunnel effect reaches its intended maximum before hard exhaustion. Keep this below 100 so the player feels pressure before their stamina is empty.");
		maximumTunnelVisionAlpha = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "MaximumTunnelVisionAlpha", 0.68f, "Maximum edge opacity of the sprint-exhaustion tunnel vision. V1.1.4 narrows the clear centre more rather than simply making the whole screen darker.");
		tunnelVisionPulseStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "TunnelVisionPulseStrength", 0.3f, "How strongly the tunnel vision gently swells with heavy breathing. This only becomes noticeable as exertion rises.");
		tunnelVisionClearRadiusAtExhaustion = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "TunnelVisionClearRadiusAtExhaustion", 0.82f, "Size of the fully clear central view at heavy exhaustion. Lower values make the field of view feel more tightly narrowed; 0.82 keeps combat readable while making fatigue unmistakable.");
		enableWindRushStreaks = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnableWindRushStreaks", true, "Draws subtle pale wind streaks that burst outward from the centre toward all screen edges during a fresh full sprint. The centre remains clear for aiming and combat.");
		windRushStreakCount = ((BaseUnityPlugin)this).Config.Bind<int>("Visuals", "WindRushStreakCount", 28, "Number of radial wind streaks. Higher values create a fuller all-angle speed field but can feel visually busy.");
		windRushStartSprintBuild = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "WindRushStartSprintBuild", 0.52f, "Sprint build percentage at which wind streaks start. This keeps them out of normal jogging and the first moments of a run.");
		windRushMaximumAlpha = ((BaseUnityPlugin)this).Config.Bind<float>(new ConfigDefinition("Visuals", "WindRushMaximumAlpha"), 0.24f, new ConfigDescription("Brightness / visibility of individual wind streaks at full sprint. This is a slider in BepInEx Configuration Manager when that mod is installed. 0.24 is the current balanced default; try 0.32 for clearer streaks or 0.40 for a much stronger speed effect.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 0.65f), Array.Empty<object>()));
		windRushTravelSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "WindRushTravelSpeed", 1.35f, "How quickly radial wind streaks travel away from the screen centre at full sprint.");
		enableCameraSway = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnableCameraSway", true, "Adds subtle sprint bob and heavier breathing sway. It patches the final camera position so it layers after Survival View's Raised Head View.");
		cameraSwayClosestZoomOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "CameraSwayClosestZoomOnly", true, "When true, camera sway appears only at closest zoom / Survival View, avoiding unwanted third-person camera motion.");
		closestZoomTolerance = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "ClosestZoomToleranceMeters", 0.08f, "Tolerance used by CameraSwayClosestZoomOnly to recognise Valheim's closest normal third-person zoom.");
		sprintBobVerticalMeters = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "SprintBobVerticalMeters", 0.013f, "Maximum vertical camera bob while sprinting at low exertion. This is deliberately noticeable in Survival View without becoming nauseating.");
		sprintBobSideMeters = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "SprintBobSideMeters", 0.009f, "Maximum sideways camera bob while sprinting at low exertion.");
		fatigueBreathSwayMeters = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "FatigueBreathSwayMeters", 0.02f, "Maximum slow breathing sway at high exertion or hard fatigue recovery. This is intentionally small so it feels heavy rather than jittery.");
		sprintSwayFrequencyLow = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "SprintSwayFrequencyLowHz", 1.45f, "Slow sprint gait frequency in cycles per second. Lower values feel steadier and less jittery.");
		sprintSwayFrequencyHigh = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "SprintSwayFrequencyHighHz", 2.15f, "Fast sprint gait frequency in cycles per second at full pace.");
		breathSwayFrequencyLow = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "BreathSwayFrequencyLowHz", 0.2f, "Slow breathing sway frequency at the beginning of visible exertion.");
		breathSwayFrequencyHigh = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "BreathSwayFrequencyHighHz", 0.48f, "Heavy breathing sway frequency near exhaustion. 0.48 Hz is about 29 breaths per minute.");
		cameraSwaySmoothingSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "CameraSwaySmoothingSeconds", 0.2f, "How gently camera sway eases toward its target. Higher values are smoother and reduce jitter.");
		coolEdgeTintStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "CoolEdgeTintStrength", 0.68f, "How much the peripheral haze shifts toward an airy blue-grey before deepening toward charcoal near exhaustion.");
		enableNativeDepthOfField = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnableNativeDepthOfField", true, "Uses Valheim's own CameraEffects depth-of-field component during heavy exertion. It focuses on the object in the centre of the view and applies only a mild depth blur.");
		depthOfFieldClosestZoomOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "DepthOfFieldClosestZoomOnly", true, "When true, exhaustion depth of field only runs at closest zoom / Survival View to keep normal third-person gameplay clear.");
		depthOfFieldStartVisualIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "DepthOfFieldStartVisualIntensity", 0.34f, "Visual-exhaustion intensity where mild focus blur begins. Tunnel tint can start earlier, but focus blur waits until exertion is meaningful.");
		depthOfFieldMaximumBlurSize = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "DepthOfFieldMaximumBlurSize", 0.55f, "Maximum native depth-of-field blur size near exhaustion. Kept deliberately modest so the screen centre remains usable in combat.");
		depthOfFieldFocalSizeAtExhaustion = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "DepthOfFieldFocalSizeAtExhaustion", 1.1f, "Focal range around the point you are looking at near exhaustion. Smaller values create a narrower, more focused view.");
		depthOfFieldFallbackFocusDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "DepthOfFieldFallbackFocusDistance", 18f, "Focus distance used when the centre camera ray does not hit terrain or an object.");
		depthOfFieldMaximumFocusDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "DepthOfFieldMaximumFocusDistance", 80f, "Maximum centre-view ray distance used for exhaustion focus.");
		flowStateBaseFov = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "FlowStateBaseFov", 60f, "Resting FOV floor. Realistic Running never drives FOV below this value.");
		flowStateMaximumFov = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "FlowStateMaximumFov", 70f, "FOV reached as a healthy run settles into flow. This replaces the retired SprintFovBoostDegrees setting.");
		pushStateFov = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "PushStateFov", 80f, "FOV reached during E-tap Pushing.");
		adrenalineStateFov = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "AdrenalineStateFov", 85f, "FOV reached during automatic Adrenaline.");
		visualTierTransitionSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "VisualTierTransitionSeconds", 1f, "Exact seconds for each transition in both directions, starting at the currently visible FOV. All tier-based effects share this transition.");
		adrenalineAudioFadeSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Adrenaline Sensory", "AudioFadeSeconds", 0.8f, "Smooth fade into and out of onset audio: game audio falls by 70% while the heartbeat rises to full clip volume.");
		exertionVisualTimeConstantSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "ExertionVisualTimeConstantSeconds", 3f, "Single exponential time constant shared by FOV, saturation, clarity, wind rush and peripheral motion blur. Applies equally as exertion rises and falls.");
		enableControlledMotionBlur = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnableControlledMotionBlur", true, "Enables masked radial scene blur in the wind-rush clear-centre zone, scaled by the shared exertion visual value. Native full-frame motion blur stays disabled.");
		enableFlowColorSaturation = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnableFlowColorSaturation", true, "Adds modest saturation from the same exertion-driven flow value as FOV and speed cues.");
		flowSaturationMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "FlowSaturationMultiplier", 1.2f, "A restrained realistic saturation multiplier at full Adrenaline visuals. Flow and Pushing use proportionally less; neutral is 1.0.");
		enableFlowClarity = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnableFlowClarity", true, "Subtle clarity from the shared smoothed exertion visual value.");
		flowClarityStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "FlowClarityStrength", 0.12f, "Conservative sharpening strength at full exertion visuals (0-0.25).");
		peripheralMotionBlurStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "PeripheralMotionBlurStrength", 0.05f, "Radial blur sample distance at full exertion visuals (0-0.08). Always zero inside the wind-rush clear centre.");
		enablePeripheralMotionAwareness = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnablePeripheralMotionAwareness", false, "Optional experimental camera-compensated moving silhouette contrast preservation. Disabled by default to retain the proven rendering. No creature recognition or fine-detail sharpening; does not undo native DOF.");
		peripheralMotionAwarenessStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "PeripheralMotionAwarenessStrength", 0.65f, "Moving broad-contrast preservation strength (0-1). Applies only outside the existing clear centre; stationary scenery is not intentionally enhanced.");
		enablePeripheralBlurOverlay = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnablePeripheralBlurOverlay", true, "Adds a soft blue-grey focus-softening overlay around the outer edge as exertion builds. It complements Valheim's native depth of field without obscuring the centre.");
		peripheralBlurStartIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "PeripheralBlurStartIntensity", 0.22f, "Visual-exhaustion intensity where the subtle peripheral blur overlay begins to appear.");
		peripheralBlurMaximumAlpha = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "PeripheralBlurMaximumAlpha", 0.24f, "Maximum opacity of the soft peripheral blur overlay near heavy exhaustion.");
		peripheralBlurClearRadiusAtExhaustion = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "PeripheralBlurClearRadiusAtExhaustion", 0.92f, "Clear central radius that remains crisp when the peripheral blur overlay is at maximum strength. Lower values create more outer-edge focus loss.");
		enableExhaustionHeartbeat = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "EnableExhaustionHeartbeat", true, "Plays the supplied double-heartbeat sample as physical exhaustion builds, then spaces the beats out and fades them during recovery.");
		heartbeatStartPressure = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "HeartbeatStartPressure", 0.42f, "Exhaustion pressure where the heartbeat first becomes audible. It remains silent during ordinary jogging and light sprinting.");
		heartbeatRecoveryBpm = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "HeartbeatRecoveryBPM", 88f, "Slowest audible heartbeat rate during the tail end of recovery.");
		heartbeatMaximumBpm = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "HeartbeatMaximumBPM", 150f, "Fastest heartbeat rate at hard exhaustion. Values above 160 tend to feel artificial with this double-beat sample.");
		heartbeatMaximumVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "HeartbeatMaximumVolume", 0.3f, "Maximum heartbeat volume at hard exhaustion. Keep low enough that Valheim combat, rain and music still remain audible.");
		heartbeatIntensitySmoothingSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "HeartbeatIntensitySmoothingSeconds", 0.75f, "How gently the heartbeat rate responds to changing exhaustion. This prevents abrupt BPM jumps when you stop running.");
		enableBloodPulse = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "EnableBloodPulse", true, "Layers a soft, low pressure whoosh swell under the heartbeat thump, plus a faint synced screen-edge pulse. Rides on the existing heartbeat pressure/BPM value; not an independent system.");
		bloodPulseMinVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "BloodPulseMinVolume", 0.035f, "Whoosh volume at rest, riding under the heartbeat.");
		bloodPulseMaxVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "BloodPulseMaxVolume", 0.35f, "Whoosh volume at full adrenaline pressure. Always kept well below the heartbeat clip's own peak volume so it never competes with the thump.");
		bloodPulseVignetteMaxAlpha = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "BloodPulseVignetteMaxAlpha", 0.1f, "Maximum opacity of the subtle screen-edge brightness/darkness pulse timed to the heartbeat. Near-subliminal at rest, only clearly perceptible under real exertion or adrenaline.");
		enableMovementAudio = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "EnableMovementAudio", true, "Plays the supplied breathing and footstep layers alongside Valheim's native surface sounds.");
		shallowBreathVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "ShallowBreathVolume", 0.18f, "Volume of Shallow_Breath.wav at run start.");
		flowBreathVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "FlowBreathVolume", 0.16f, "Volume of Medium_Flow_Breathing.wav during a settled run.");
		heavyBreathVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "HeavyBreathVolume", 0.28f, "Volume of Breathing_Heavy.wav on hills, Pushing and Adrenaline.");
		stompFootstepVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "StompFootstepVolume", 0.16f, "Volume of Stomps_Footsteps.wav during the initial run phase.");
		runStartAudioSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "RunStartAudioSeconds", 15f, "Initial stomp-footstep phase length. Normal breathing and flow visuals use exertion thresholds instead.");
		movementAudioCrossfadeSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "MovementAudioCrossfadeSeconds", 0.8f, "Smooth breathing/footstep transitions in seconds (0 disables fading, maximum 3). Outgoing clips stop when their fade finishes; run phase timing stays unchanged.");
		enableBaselineExhaustionBreathing = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "EnableBaselineExhaustionBreathing", true, "Plays abrupt gasping heavy breathing when normal sprint stamina hits the exhaustion threshold.");
		exhaustionBreathRestRecoverySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "ExhaustionBreathRestRecoverySeconds", 60f, "Baseline exhaustion breathing reaches calm after this many seconds while standing or walking.");
		exhaustionBreathJogRecoverySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "ExhaustionBreathJogRecoverySeconds", 120f, "Baseline exhaustion breathing reaches calm after this many seconds while exhausted and continuing to jog.");
		exhaustionBreathInitialVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "ExhaustionBreathInitialVolume", 0.42f, "Immediate heavy-breath volume when normal sprint exhaustion begins.");
		exhaustionBreathInitialPitch = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "ExhaustionBreathInitialPitch", 1.15f, "Initial heavy-breath clip pitch. The gasp rate itself slows through timed retriggers during recovery.");
		showRecoverySeconds = ((BaseUnityPlugin)this).Config.Bind<bool>("Interface", "ShowRecoverySeconds", false, "Shows the remaining recovery seconds beside the red recovery bar. Off by default.");
	}

	private void MigratePerceptibilityDefaults()
	{
		bool flag = false;
		if (Mathf.Abs(sprintStartSpeedFraction.Value - 0.78f) < 0.001f)
		{
			sprintStartSpeedFraction.Value = 0.72f;
			flag = true;
		}
		if (Mathf.Abs(topSprintSpeedMultiplier.Value - 1.2f) < 0.001f || Mathf.Abs(topSprintSpeedMultiplier.Value - 1.32f) < 0.001f)
		{
			topSprintSpeedMultiplier.Value = 1.45f;
			flag = true;
		}
		if (Mathf.Abs(highExertionStart.Value - 55f) < 0.001f)
		{
			highExertionStart.Value = 35f;
			flag = true;
		}
		if (Mathf.Abs(highExertionRunSpeedMultiplier.Value - 0.89f) < 0.001f)
		{
			highExertionRunSpeedMultiplier.Value = 0.84f;
			flag = true;
		}
		if (Mathf.Abs(exhaustionTriggerStaminaPercentage.Value - 0.02f) < 0.001f)
		{
			exhaustionTriggerStaminaPercentage.Value = 0.08f;
			flag = true;
		}
		if (Mathf.Abs(maximumTunnelVisionAlpha.Value - 0.42f) < 0.001f || Mathf.Abs(maximumTunnelVisionAlpha.Value - 0.58f) < 0.001f)
		{
			maximumTunnelVisionAlpha.Value = 0.78f;
			flag = true;
		}
		if (Mathf.Abs(sprintBobVerticalMeters.Value - 0.018f) < 0.001f)
		{
			sprintBobVerticalMeters.Value = 0.032f;
			flag = true;
		}
		if (Mathf.Abs(sprintBobSideMeters.Value - 0.012f) < 0.001f)
		{
			sprintBobSideMeters.Value = 0.022f;
			flag = true;
		}
		if (Mathf.Abs(fatigueBreathSwayMeters.Value - 0.032f) < 0.001f)
		{
			fatigueBreathSwayMeters.Value = 0.02f;
			flag = true;
		}
		if (Mathf.Abs(sprintBobVerticalMeters.Value - 0.032f) < 0.001f)
		{
			sprintBobVerticalMeters.Value = 0.013f;
			flag = true;
		}
		if (Mathf.Abs(sprintBobSideMeters.Value - 0.022f) < 0.001f)
		{
			sprintBobSideMeters.Value = 0.009f;
			flag = true;
		}
		if (Mathf.Abs(fatigueBreathSwayMeters.Value - 0.058f) < 0.001f)
		{
			fatigueBreathSwayMeters.Value = 0.02f;
			flag = true;
		}
		if (Mathf.Abs(maximumTunnelVisionAlpha.Value - 0.78f) < 0.001f || Mathf.Abs(maximumTunnelVisionAlpha.Value - 0.62f) < 0.001f)
		{
			maximumTunnelVisionAlpha.Value = 0.68f;
			flag = true;
		}
		if (Mathf.Abs(coolEdgeTintStrength.Value - 0.62f) < 0.001f)
		{
			coolEdgeTintStrength.Value = 0.68f;
			flag = true;
		}
		if (Mathf.Abs(depthOfFieldStartVisualIntensity.Value - 0.34f) < 0.001f)
		{
			depthOfFieldStartVisualIntensity.Value = 0.26f;
			flag = true;
		}
		if (Mathf.Abs(depthOfFieldMaximumBlurSize.Value - 0.55f) < 0.001f)
		{
			depthOfFieldMaximumBlurSize.Value = 0.7f;
			flag = true;
		}
		if (Mathf.Abs(depthOfFieldFocalSizeAtExhaustion.Value - 1.1f) < 0.001f)
		{
			depthOfFieldFocalSizeAtExhaustion.Value = 0.9f;
			flag = true;
		}
		if (windRushStreakCount.Value == 12)
		{
			windRushStreakCount.Value = 28;
			flag = true;
		}
		if (Mathf.Abs(windRushMaximumAlpha.Value - 0.2f) < 0.001f)
		{
			windRushMaximumAlpha.Value = 0.24f;
			flag = true;
		}
		if (flag)
		{
			((BaseUnityPlugin)this).Config.Save();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Realistic Running: migrated untouched defaults to V1.1.8 slightly clearer radial wind-rush streaks.");
		}
	}

	private void MigrateEscapeSafetyDefaults()
	{
		if (Mathf.Abs(exhaustedJogSeconds.Value - 8f) < 0.001f && Mathf.Abs(exhaustedJogSpeedMultiplier.Value - 0.84f) < 0.001f && Mathf.Abs(recoveryStaminaPercentage.Value - 0.38f) < 0.001f && Mathf.Abs(recoveryExertionPercentage.Value - 45f) < 0.001f)
		{
			exhaustedJogSeconds.Value = 5.5f;
			exhaustedJogSpeedMultiplier.Value = 0.88f;
			recoveryStaminaPercentage.Value = 0.28f;
			recoveryExertionPercentage.Value = 55f;
			((BaseUnityPlugin)this).Config.Save();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Realistic Running: migrated the exhausted-sprint recovery defaults to the ground-floor escape safety values.");
		}
	}

	private void MigratePushStateDefaults()
	{
		bool flag = false;
		if (Mathf.Abs(adrenalineOnsetSeconds.Value - 7f) < 0.001f)
		{
			adrenalineOnsetSeconds.Value = 5f;
			flag = true;
		}
		if (Mathf.Abs(pushTapSustainSeconds.Value - 0.5f) < 0.001f)
		{
			pushTapSustainSeconds.Value = 1.5f;
			flag = true;
		}
		if (Mathf.Abs(pushTapRatePerSecond.Value - 4f) < 0.001f)
		{
			pushTapRatePerSecond.Value = 3f;
			flag = true;
		}
		if (Mathf.Abs(adrenalineSpeedMultiplier.Value - 5.5f) < 0.001f || Mathf.Abs(adrenalineSpeedMultiplier.Value - 4.7f) < 0.001f || Mathf.Abs(adrenalineSpeedMultiplier.Value - 4.9f) < 0.001f || Mathf.Abs(adrenalineSpeedMultiplier.Value - 3.3f) < 0.001f || Mathf.Abs(adrenalineSpeedMultiplier.Value - 2.7f) < 0.001f || Mathf.Abs(adrenalineSpeedMultiplier.Value - 2.4f) < 0.001f)
		{
			adrenalineSpeedMultiplier.Value = 2.1f;
			flag = true;
		}
		if (Mathf.Abs(adrenalineSpeedMultiplier.Value - 2.1f) < 0.001f)
		{
			adrenalineSpeedMultiplier.Value = 1.1f;
			flag = true;
		}
		if (Mathf.Abs(adrenalineSpeedMultiplier.Value - 1.5f) < 0.001f)
		{
			adrenalineSpeedMultiplier.Value = 1.1f;
			flag = true;
		}
		if (Mathf.Abs(pushSpeedMultiplier.Value - 2.5f) < 0.001f || Mathf.Abs(pushSpeedMultiplier.Value - 1.5f) < 0.001f || pushSpeedMultiplier.Value < 1f)
		{
			pushSpeedMultiplier.Value = 1f;
			flag = true;
		}
		if (flag)
		{
			((BaseUnityPlugin)this).Config.Save();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Realistic Running: migrated the push-state defaults.");
		}
	}

	private void MigrateFlowFovDefaults()
	{
		bool flag = false;
		if (Mathf.Abs(pushStateFov.Value - 77f) < 0.001f)
		{
			pushStateFov.Value = 80f;
			flag = true;
		}
		if (Mathf.Abs(adrenalineStateFov.Value - 83f) < 0.001f)
		{
			adrenalineStateFov.Value = 85f;
			flag = true;
		}
		if (Mathf.Abs(visualTierTransitionSeconds.Value - 4.5f) < 0.001f || Mathf.Abs(visualTierTransitionSeconds.Value - 3.5f) < 0.001f)
		{
			visualTierTransitionSeconds.Value = 1f;
			flag = true;
		}
		if (Mathf.Abs(flowSaturationMultiplier.Value - 1.15f) < 0.001f || Mathf.Abs(flowSaturationMultiplier.Value - 1.25f) < 0.001f)
		{
			flowSaturationMultiplier.Value = 1.2f;
			flag = true;
		}
		if (Mathf.Abs(peripheralMotionBlurStrength.Value - 0.018f) < 0.0001f)
		{
			peripheralMotionBlurStrength.Value = 0.05f;
			flag = true;
		}
		if (Mathf.Abs(flowStateMaximumFov.Value - 75f) < 0.001f)
		{
			flowStateMaximumFov.Value = 70f;
			flag = true;
		}
		if (flag)
		{
			((BaseUnityPlugin)this).Config.Save();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Realistic Running: migrated untouched flow visual defaults to the restrained staged running profile.");
		}
	}

	private void MigrateMovementAudioDefaults()
	{
		if (Mathf.Abs(runStartAudioSeconds.Value - 2f) < 0.001f || Mathf.Abs(runStartAudioSeconds.Value - 7.5f) < 0.001f)
		{
			runStartAudioSeconds.Value = 15f;
			((BaseUnityPlugin)this).Config.Save();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Realistic Running: migrated the shallow-breath phase to 15 seconds.");
		}
	}

	private void InstallPatches()
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Expected O, but got Unknown
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Expected O, but got Unknown
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Expected O, but got Unknown
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Expected O, but got Unknown
		//IL_010f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0115: Expected O, but got Unknown
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		//IL_018c: Unknown result type (might be due to invalid IL or missing references)
		//IL_019b: Expected O, but got Unknown
		//IL_019b: Expected O, but got Unknown
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b7: Expected O, but got Unknown
		//IL_020f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0224: Unknown result type (might be due to invalid IL or missing references)
		//IL_0233: Expected O, but got Unknown
		//IL_0233: Expected O, but got Unknown
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_024f: Expected O, but got Unknown
		//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0308: Expected O, but got Unknown
		//IL_031d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0324: Expected O, but got Unknown
		//IL_03a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b9: Expected O, but got Unknown
		harmony = new Harmony("com.marccunningham.survivalmovementexertion");
		HarmonyMethod val = new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerSetControlsPrefix", (Type[])null);
		val.priority = 0;
		val.after = new string[1] { "com.marccunningham.survivalview" };
		setControlsPatchInstalled = TryPatch(FindMethod(typeof(Player), "SetControls", null), val, null, null, "Player.SetControls(...)");
		HarmonyMethod val2 = new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerGetJogSpeedFactorPostfix", (Type[])null);
		val2.priority = 0;
		jogSpeedPatchInstalled = TryPatch(FindMethod(typeof(Player), "GetJogSpeedFactor", Type.EmptyTypes), null, val2, null, "Player.GetJogSpeedFactor()");
		HarmonyMethod val3 = new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerGetRunSpeedFactorPostfix", (Type[])null);
		val3.priority = 0;
		runSpeedPatchInstalled = TryPatch(FindMethod(typeof(Player), "GetRunSpeedFactor", Type.EmptyTypes), null, val3, null, "Player.GetRunSpeedFactor()");
		HarmonyMethod val4 = new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerCheckRunPostfix", (Type[])null);
		val4.priority = 0;
		val4.after = new string[1] { "com.marccunningham.survivalview" };
		checkRunPatchInstalled = TryPatch(FindMethod(typeof(Player), "CheckRun", new Type[2]
		{
			typeof(Vector3),
			typeof(float)
		}), new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerCheckRunPrefix", (Type[])null), val4, new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerCheckRunFinalizer", (Type[])null), "Player.CheckRun(Vector3, float)");
		HarmonyMethod val5 = new HarmonyMethod(typeof(SurvivalMovementPatches), "CharacterUpdateWalkingPrefix", (Type[])null);
		val5.priority = 0;
		val5.after = new string[1] { "com.marccunningham.survivalview" };
		recoveryWalkingPatchInstalled = TryPatch(FindMethod(typeof(Character), "UpdateWalking", new Type[1] { typeof(float) }), val5, new HarmonyMethod(typeof(SurvivalMovementPatches), "CharacterUpdateWalkingPostfix", (Type[])null), new HarmonyMethod(typeof(SurvivalMovementPatches), "CharacterUpdateWalkingFinalizer", (Type[])null), "Character.UpdateWalking(float) recovery enforcement");
		HarmonyMethod val6 = new HarmonyMethod(typeof(SurvivalMovementPatches), "GameCameraGetCameraPositionPostfix", (Type[])null);
		val6.priority = 0;
		val6.after = new string[1] { "com.marccunningham.survivalview" };
		cameraPositionPatchInstalled = TryPatch(FindMethod(typeof(GameCamera), "GetCameraPosition", new Type[3]
		{
			typeof(float),
			typeof(Vector3).MakeByRefType(),
			typeof(Quaternion).MakeByRefType()
		}), null, val6, null, "GameCamera.GetCameraPosition(float, out Vector3, out Quaternion)");
		depthOfFieldPatchInstalled = TryPatch(FindMethod(typeof(CameraEffects), "UpdateDOF", Type.EmptyTypes), null, new HarmonyMethod(typeof(SurvivalMovementPatches), "CameraEffectsUpdateDofPostfix", (Type[])null), null, "CameraEffects.UpdateDOF()");
		HarmonyMethod val7 = new HarmonyMethod(typeof(SurvivalMovementPatches), "GameCameraUpdateCameraFovPostfix", (Type[])null);
		val7.priority = 0;
		val7.after = new string[1] { "com.marccunningham.survivalview" };
		cameraFovPatchInstalled = TryPatch(FindMethod(typeof(GameCamera), "UpdateCamera", new Type[1] { typeof(float) }), null, val7, null, "GameCamera.UpdateCamera(float) FOV authority");
		cameraFovSourcePatchInstalled = TryPatch(FindMethod(typeof(GameCamera), "UpdateFOV", Type.EmptyTypes), new HarmonyMethod(typeof(SurvivalMovementPatches), "GameCameraUpdateFovPrefix", (Type[])null), null, null, "GameCamera.UpdateFOV() shared tier authority");
		cameraFovLatePatchInstalled = TryPatch(FindMethod(typeof(GameCamera), "LateUpdate", Type.EmptyTypes), null, val7, null, "GameCamera.LateUpdate() final FOV authority");
	}

	private bool TryPatch(MethodInfo target, HarmonyMethod prefix, HarmonyMethod postfix, HarmonyMethod finalizer, string targetName)
	{
		if (target == null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Realistic Running: could not find " + targetName + ". That feature is disabled."));
			return false;
		}
		try
		{
			harmony.Patch((MethodBase)target, prefix, postfix, (HarmonyMethod)null, finalizer, (HarmonyMethod)null);
			LogVerbose("Realistic Running: patched " + targetName + ".");
			return true;
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Realistic Running: failed to patch " + targetName + ": " + ex));
			return false;
		}
	}

	private bool HasSurvivalViewAuthority()
	{
		return modEnabled != null && modEnabled.Value;
	}

	private void TryClaimSurvivalViewAuthority()
	{
		if (survivalViewAuthorityClaimed)
		{
			return;
		}
		Type type = Type.GetType("SurvivalView.SurvivalViewBridge, SurvivalView", throwOnError: false);
		if (type == null)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				if (string.Equals(assembly.GetName().Name, "SurvivalView", StringComparison.OrdinalIgnoreCase))
				{
					type = assembly.GetType("SurvivalView.SurvivalViewBridge", throwOnError: false);
					if (type != null)
					{
						break;
					}
				}
			}
		}
		if (type == null)
		{
			return;
		}
		FieldInfo field = type.GetField("ExternalFovAuthority", BindingFlags.Static | BindingFlags.Public);
		FieldInfo field2 = type.GetField("ExternalMovementAuthority", BindingFlags.Static | BindingFlags.Public);
		if (field == null || field2 == null || field.FieldType != typeof(Func<bool>) || field2.FieldType != typeof(Func<bool>))
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Realistic Running: Survival View bridge has an unsupported authority contract.");
			return;
		}
		try
		{
			Delegate value = Delegate.CreateDelegate(typeof(Func<bool>), this, "HasSurvivalViewAuthority");
			field.SetValue(null, value);
			field2.SetValue(null, value);
			survivalViewExternalFovAuthorityField = field;
			survivalViewExternalMovementAuthorityField = field2;
			survivalViewAuthorityDelegate = value;
			survivalViewAuthorityClaimed = true;
			LogVerbose("Realistic Running: claimed Survival View FOV and movement authority through its optional bridge.");
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Realistic Running: could not claim Survival View authority: " + ex.Message));
		}
	}

	private void ReleaseSurvivalViewAuthority()
	{
		if (!survivalViewAuthorityClaimed)
		{
			return;
		}
		try
		{
			if (survivalViewExternalFovAuthorityField != null && object.Equals(survivalViewExternalFovAuthorityField.GetValue(null), survivalViewAuthorityDelegate))
			{
				survivalViewExternalFovAuthorityField.SetValue(null, null);
			}
			if (survivalViewExternalMovementAuthorityField != null && object.Equals(survivalViewExternalMovementAuthorityField.GetValue(null), survivalViewAuthorityDelegate))
			{
				survivalViewExternalMovementAuthorityField.SetValue(null, null);
			}
		}
		catch
		{
		}
		finally
		{
			survivalViewExternalFovAuthorityField = null;
			survivalViewExternalMovementAuthorityField = null;
			survivalViewAuthorityDelegate = null;
			survivalViewAuthorityClaimed = false;
		}
	}

	private static MethodInfo FindMethod(Type type, string methodName, Type[] parameterTypes)
	{
		if (parameterTypes != null)
		{
			return type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null);
		}
		MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		for (int i = 0; i < methods.Length; i++)
		{
			if (methods[i].Name == methodName)
			{
				return methods[i];
			}
		}
		return null;
	}

	private bool IsMovementEligible(Player player)
	{
		return modEnabled.Value && (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer && !((Character)player).IsDead() && !((Character)player).IsAttached() && !((Character)player).IsSwimming() && !((Character)player).IsFlying();
	}

	private void ResetTransientMovementState()
	{
		visualInputPlayer = null;
		visualRawMovementRequested = (visualSprintRequested = false);
		Player localPlayer = Player.m_localPlayer;
		bool flag = (Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead();
		smoothedInputMagnitude = Mathf.MoveTowards(smoothedInputMagnitude, 0f, Time.deltaTime * 5f);
		sprintBuild = Mathf.MoveTowards(sprintBuild, 0f, Time.deltaTime * 4f);
		exertion = Mathf.MoveTowards(exertion, 0f, Time.deltaTime * Mathf.Max(0f, exertionRecoveryPerSecond.Value));
		wasSprinting = false;
		if (flag)
		{
			exhaustedJogRemaining = 0f;
			fatigueRecoveryActive = false;
			baselineMovementRecoveryActive = false;
			pushState = PushState.Normal;
			pushStateRemaining = 0f;
			pushMovementRecoveryActive = false;
			pushMinimumRecoveryRemaining = 0f;
			tapTimes.Clear();
			fastTapStartedAt = -1f;
			lastFastTapSatisfiedTime = -1f;
			lastObservedStaminaForAdrenalineRefund = -1f;
			pushStateLoaded = false;
			pushStateSaveTimer = 0f;
			baselineExhaustionBreathingActive = false;
			baselineExhaustionBreathingCompleted = false;
			baselineExhaustionBreathingProgress = 0f;
			baselineSprintAttemptWasHeld = false;
			baselineExhaustionBreathingStatus = "idle";
		}
		cachedClimbingSlope = false;
		movementAudioSequence.Reset();
		lastRunDrainMultiplier = 1f;
		smoothedCameraSwayVertical = 0f;
		smoothedCameraSwaySide = 0f;
		cameraSwayVerticalVelocity = 0f;
		cameraSwaySideVelocity = 0f;
		latestCameraDistance = float.MaxValue;
		latestCameraMinimumDistance = float.MaxValue;
		heartbeatCurrentPressure = 0f;
		heartbeatPressureVelocity = 0f;
		heartbeatCurrentBpm = 0f;
		heartbeatNextBeatTime = Time.unscaledTime + 0.1f;
		lastHeartbeatBeatTime = -999f;
		bloodPulseVignetteAlpha = 0f;
		StopHeartbeatAudio();
		StopBloodPulseAudio();
		StopMovementAudio();
		ResetWorldFactors();
	}

	private void ResetWorldFactors()
	{
		terrainSpeedMultiplier = 1f;
		terrainDrainMultiplier = 1f;
		terrainExertionMultiplier = 1f;
		weatherSpeedMultiplier = 1f;
		weatherDrainMultiplier = 1f;
		weatherExertionMultiplier = 1f;
		weatherRecoveryMultiplier = 1f;
		injurySpeedMultiplier = 1f;
		injuryExertionMultiplier = 1f;
		cachedSlopeAngle = 0f;
		cachedWet = false;
		cachedCold = false;
		cachedFreezing = false;
	}

	private void RefreshWorldFactors(Player player)
	{
		UpdateTerrainFactors(player);
		UpdateWeatherFactors(player);
		UpdateInjuryCompatibility(player);
	}

	private void UpdateTerrainFactors(Player player)
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: 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)
		//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_00df: 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_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_010f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0114: Unknown result type (might be due to invalid IL or missing references)
		terrainSpeedMultiplier = 1f;
		terrainDrainMultiplier = 1f;
		terrainExertionMultiplier = 1f;
		cachedSlopeAngle = 0f;
		cachedClimbingSlope = false;
		if (!enableHillEffects.Value || !((Character)player).IsOnGround())
		{
			return;
		}
		Vector3 moveDir = ((Character)player).GetMoveDir();
		moveDir.y = 0f;
		if (((Vector3)(ref moveDir)).sqrMagnitude <= 1.0000001E-06f)
		{
			return;
		}
		Vector3 lastGroundNormal = ((Character)player).GetLastGroundNormal();
		if (((Vector3)(ref lastGroundNormal)).sqrMagnitude <= 0.01f)
		{
			return;
		}
		((Vector3)(ref lastGroundNormal)).Normalize();
		cachedSlopeAngle = Vector3.Angle(lastGroundNormal, Vector3.up);
		if (!(cachedSlopeAngle <= 0.01f))
		{
			Vector3 val = Vector3.ProjectOnPlane(Vector3.up, lastGroundNormal);
			if (!(((Vector3)(ref val)).sqrMagnitude <= 0.0001f))
			{
				((Vector3)(ref val)).Normalize();
				float num = Vector3.Dot(((Vector3)(ref moveDir)).normalized, val);
				cachedClimbingSlope = num > 0.01f;
				terrainDrainMultiplier = 1f + Mathf.Clamp(flatSlopeDrainBonus.Value, 0f, 0.5f);
			}
		}
	}

	private void UpdateWeatherFactors(Player player)
	{
		weatherSpeedMultiplier = 1f;
		weatherDrainMultiplier = 1f;
		weatherExertionMultiplier = 1f;
		weatherRecoveryMultiplier = 1f;
		cachedWet = false;
		cachedCold = false;
		cachedFreezing = false;
		if (enableWeatherEffects.Value)
		{
			SEMan sEMan = ((Character)player).GetSEMan();
			bool flag = sEMan != null && sEMan.HaveStatusEffect(SEMan.s_statusEffectWet);
			cachedWet = flag || EnvMan.IsWet();
			cachedFreezing = EnvMan.IsFreezing();
			cachedCold = !cachedFreezing && EnvMan.IsCold();
			if (cachedWet)
			{
				weatherSpeedMultiplier *= Mathf.Clamp(wetSpeedMultiplier.Value, 0.7f, 1f);
				weatherDrainMultiplier *= Mathf.Max(1f, wetDrainMultiplier.Value);
				weatherExertionMultiplier *= Mathf.Max(1f, wetExertionMultiplier.Value);
				weatherRecoveryMultiplier *= 0.85f;
			}
			if (cachedFreezing)
			{
				weatherSpeedMultiplier *= Mathf.Clamp(freezingSpeedMultiplier.Value, 0.7f, 1f);
				weatherDrainMultiplier *= Mathf.Max(1f, freezingDrainMultiplier.Value);
				weatherExertionMultiplier *= Mathf.Max(1f, freezingExertionMultiplier.Value);
				weatherRecoveryMultiplier *= 0.72f;
			}
			else if (cachedCold)
			{
				weatherDrainMultiplier *= Mathf.Max(1f, coldDrainMultiplier.Value);
				weatherExertionMultiplier *= Mathf.Max(1f, coldExertionMultiplier.Value);
				weatherRecoveryMultiplier *= 0.88f;
			}
		}
	}

	private void UpdateInjuryCompatibility(Player player)
	{
		injurySpeedMultiplier = 1f;
		injuryExertionMultiplier = 1f;
		if (!enableInjuryCompatibility.Value)
		{
			return;
		}
		ResolveInjuryReflection();
		if (!injuryReflectionUsable)
		{
			return;
		}
		try
		{
			object value = injuryInstanceField.GetValue(null);
			if (value != null && (bool)injuryIsActiveForMethod.Invoke(value, new object[1] { player }))
			{
				float num = Mathf.Clamp((float)injuryRunSpeedMultiplierMethod.Invoke(value, null), 0.3f, 1f);
				if (applyInjurySpeedCompatibilityPenalty.Value)
				{
					injurySpeedMultiplier = num;
				}
				float num2 = 1f - num;
				injuryExertionMultiplier = 1f + num2 * Mathf.Max(0f, injuryExertionPenaltyStrength.Value);
			}
		}
		catch
		{
			injuryReflectionUsable = false;
			injurySpeedMultiplier = 1f;
			injuryExertionMultiplier = 1f;
		}
	}

	private void ResolveInjuryReflection()
	{
		if (injuryReflectionUsable)
		{
			return;
		}
		if (injuryPluginType == null)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			for (int i = 0; i < assemblies.Length; i++)
			{
				Type type = assemblies[i].GetType("YoureInjured.YoureInjuredPlugin");
				if (type != null)
				{
					injuryPluginType = type;
					break;
				}
			}
		}
		if (!(injuryPluginType == null))
		{
			injuryInstanceField = injuryPluginType.GetField("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			injuryIsActiveForMethod = injuryPluginType.GetMethod("IsActiveFor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Player) }, null);
			injuryRunSpeedMultiplierMethod = injuryPluginType.GetMethod("GetRunSpeedMultiplier", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			injuryReflectionUsable = injuryInstanceField != null && injuryIsActiveForMethod != null && injuryRunSpeedMultiplierMethod != null;
		}
	}

	private void TryLoadHeartbeatAudio()
	{
		if (!enableExhaustionHeartbeat.Value)
		{
			heartbeatStatus = "disabled in config";
			return;
		}
		try
		{
			string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			if (string.IsNullOrEmpty(directoryName))
			{
				heartbeatStatus = "plugin folder could not be resolved";
				return;
			}
			string[] array = new string[4]
			{
				Path.Combine(directoryName, "assets", "heartbeat_double.wav"),
				Path.Combine(directoryName, "heartbeat_double.wav"),
				Path.Combine(directoryName, "assets", "untitled.wav"),
				Path.Combine(directoryName, "untitled.wav")
			};
			string text = null;
			for (int i = 0; i < array.Length; i++)
			{
				if (File.Exists(array[i]))
				{
					text = array[i];
					break;
				}
			}
			if (string.IsNullOrEmpty(text))
			{
				heartbeatStatus = "missing assets/heartbeat_double.wav";
				return;
			}
			if (!TryReadWaveFile(text, out var samples, out var channels, out var sampleRate, out var status))
			{
				heartbeatStatus = "could not decode WAV: " + status;
				return;
			}
			Type type = FindLoadedType("UnityEngine.AudioClip");
			Type type2 = FindLoadedType("UnityEngine.AudioSource");
			if (type == null || type2 == null)
			{
				heartbeatStatus = "Unity audio types were unavailable";
				return;
			}
			MethodInfo method = type.GetMethod("Create", BindingFlags.Static | BindingFlags.Public, null, new Type[5]
			{
				typeof(string),
				typeof(int),
				typeof(int),
				typeof(int),
				typeof(bool)
			}, null);
			MethodInfo method2 = type.GetMethod("SetData", BindingFlags.Instance | BindingFlags.Public, null, new Type[2]
			{
				typeof(float[]),
				typeof(int)
			}, null);
			if (method == null || method2 == null)
			{
				heartbeatStatus = "Unity AudioClip methods were unavailable";
				return;
			}
			int num = samples.Length / Mathf.Max(1, channels);
			object obj = method.Invoke(null, new object[5] { "SurvivalMovementExertion_Heartbeat", num, channels, sampleRate, false });
			if (obj == null)
			{
				heartbeatStatus = "Unity could not create the heartbeat clip";
				return;
			}
			if (!(bool)method2.Invoke(obj, new object[2] { samples, 0 }))
			{
				Object.Destroy((Object)((obj is Object) ? obj : null));
				heartbeatStatus = "Unity rejected the heartbeat sample data";
				return;
			}
			Component val = ((Component)this).gameObject.AddComponent(type2);
			if ((Object)(object)val == (Object)null)
			{
				Object.Destroy((Object)((obj is Object) ? obj : null));
				heartbeatStatus = "Unity could not create the heartbeat audio source";
				return;
			}
			SetNumericProperty(type2, val, "spatialBlend", 0f);
			SetBooleanProperty(type2, val, "loop", value: false);
			SetBooleanProperty(type2, val, "playOnAwake", value: false);
			SetNumericProperty(type2, val, "volume", 1f);
			MethodInfo method3 = type2.GetMethod("PlayOneShot", BindingFlags.Instance | BindingFlags.Public, null, new Type[2]
			{
				type,
				typeof(float)
			}, null);
			MethodInfo method4 = type2.GetMethod("Stop", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null);
			if (method3 == null)
			{
				Object.Destroy((Object)(object)val);
				Object.Destroy((Object)((obj is Object) ? obj : null));
				heartbeatStatus = "Unity AudioSource.PlayOneShot was unavailable";
				return;
			}
			heartbeatAudioSource = val;
			heartbeatClip = (Object)((obj is Object) ? obj : null);
			heartbeatPlayOneShotMethod = method3;
			heartbeatStopMethod = method4;
			heartbeatAssetPath = text;
			heartbeatNextBeatTime = Time.unscaledTime + 0.2f;
			heartbeatStatus = "ready " + sampleRate + " Hz, " + channels + " channel(s), " + num + " frames";
		}
		catch (Exception ex)
		{
			heartbeatStatus = "load exception: " + ex.GetType().Name;
		}
	}

	private void TryLoadBloodPulseAudio()
	{
		if (!enableBloodPulse.Value)
		{
			bloodPulseStatus = "disabled in config";
			return;
		}
		try
		{
			string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			if (string.IsNullOrEmpty(directoryName))
			{
				bloodPulseStatus = "plugin folder could not be resolved";
				return;
			}
			string[] array = new string[3]
			{
				Path.Combine(directoryName, "assets", "Whoosh_Effect.wav"),
				Path.Combine(directoryName, "Whoosh_Effect.wav"),
				Path.Combine(directoryName, "NEW SFX", "Whoosh_Effect.wav")
			};
			string text = null;
			for (int i = 0; i < array.Length; i++)
			{
				if (File.Exists(array[i]))
				{
					text = array[i];
					break;
				}
			}
			if (string.IsNullOrEmpty(text))
			{
				bloodPulseStatus = "missing assets/Whoosh_Effect.wav";
				return;
			}
			if (!TryReadWaveFile(text, out var samples, out var channels, out var sampleRate, out var status))
			{
				bloodPulseStatus = "could not decode WAV: " + status;
				return;
			}
			Type type = FindLoadedType("UnityEngine.AudioClip");
			Type type2 = FindLoadedType("UnityEngine.AudioSource");
			if (type == null || type2 == null)
			{
				bloodPulseStatus = "Unity audio types were unavailable";
				return;
			}
			MethodInfo method = type.GetMethod("Create", BindingFlags.Static | BindingFlags.Public, null, new Type[5]
			{
				typeof(string),
				typeof(int),
				typeof(int),
				typeof(int),
				typeof(bool)
			}, null);
			MethodInfo method2 = type.GetMethod("SetData", BindingFlags.Instance | BindingFlags.Public, null, new Type[2]
			{
				typeof(float[]),
				typeof(int)
			}, null);
			if (method == null || method2 == null)
			{
				blood