Decompiled source of RealisticRunning v1.2.1

RealisticRunning.dll

Decompiled a day ago
using System;
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;

[BepInPlugin("com.marccunningham.survivalmovementexertion", "Realistic Running", "1.2.1")]
[BepInProcess("valheim.exe")]
public sealed class SurvivalMovementExertionPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "com.marccunningham.survivalmovementexertion";

	public const string PluginName = "Realistic Running";

	public const string PluginVersion = "1.2.1";

	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;

	internal static SurvivalMovementExertionPlugin Instance;

	private ConfigEntry<bool> modEnabled;

	private ConfigEntry<KeyCode> diagnosticKey;

	private ConfigEntry<bool> showDiagnosticHud;

	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<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<bool> enableSprintFovBoost;

	private ConfigEntry<float> sprintFovBoostDegrees;

	private ConfigEntry<float> sprintFovBoostSmoothingSeconds;

	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 Harmony harmony;

	private bool setControlsPatchInstalled;

	private bool jogSpeedPatchInstalled;

	private bool runSpeedPatchInstalled;

	private bool checkRunPatchInstalled;

	private bool cameraPositionPatchInstalled;

	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 wasSprinting;

	private float lastRunDrainMultiplier = 1f;

	private float factorRefreshTimer = 999f;

	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 baseCameraFieldOfView = -1f;

	private float smoothedSprintFovBoost;

	private float sprintFovBoostVelocity;

	private Component heartbeatAudioSource;

	private Object heartbeatClip;

	private MethodInfo heartbeatPlayOneShotMethod;

	private MethodInfo heartbeatStopMethod;

	private float heartbeatNextBeatTime;

	private float heartbeatCurrentPressure;

	private float heartbeatPressureVelocity;

	private float heartbeatCurrentBpm;

	private string heartbeatStatus = "not loaded";

	private string heartbeatAssetPath = string.Empty;

	private FieldInfo cameraEffectsDofField;

	private FieldInfo cameraEffectsDofRayMaskField;

	private MemberInfo dofFocusDistanceMember;

	private MemberInfo dofFocalSizeMember;

	private MemberInfo dofMaxBlurSizeMember;

	private MemberInfo dofApertureMember;

	private bool depthOfFieldReflectionReady;

	private bool depthOfFieldAvailable;

	private string depthOfFieldStatus = "not resolved";

	private Type injuryPluginType;

	private FieldInfo injuryInstanceField;

	private MethodInfo injuryIsActiveForMethod;

	private MethodInfo injuryRunSpeedMultiplierMethod;

	private bool injuryReflectionUsable;

	private Texture2D[] tunnelTextures;

	private Texture2D[] peripheralBlurTextures;

	private WindStreak[] windStreaks;

	private GUIStyle diagnosticStyle;

	private void Awake()
	{
		Instance = this;
		BindConfig();
		MigratePerceptibilityDefaults();
		MigrateEscapeSafetyDefaults();
		InstallPatches();
		TryLoadHeartbeatAudio();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Realistic Running 1.2.1 loaded. WindRushMaximumAlpha is now range-limited for a Configuration Manager slider, so wind-streak visibility can be tuned without rebuilding. Press F8 for diagnostics.");
	}

	private void OnDestroy()
	{
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
		StopHeartbeatAudio();
		if ((Object)(object)heartbeatAudioSource != (Object)null)
		{
			Object.Destroy((Object)(object)heartbeatAudioSource);
			heartbeatAudioSource = null;
		}
		if (heartbeatClip != (Object)null)
		{
			Object.Destroy(heartbeatClip);
			heartbeatClip = null;
		}
		DestroyTunnelTextures();
		DestroyPeripheralBlurTextures();
		windStreaks = null;
		if ((Object)(object)Instance == (Object)(object)this)
		{
			Instance = null;
		}
	}

	private void Update()
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		if (Input.GetKeyDown(diagnosticKey.Value))
		{
			WriteDiagnostic();
		}
		Player localPlayer = Player.m_localPlayer;
		if (!IsMovementEligible(localPlayer))
		{
			ResetTransientMovementState();
			return;
		}
		factorRefreshTimer += Time.deltaTime;
		if (factorRefreshTimer >= Mathf.Max(0.05f, factorRefreshSeconds.Value))
		{
			factorRefreshTimer = 0f;
			RefreshWorldFactors(localPlayer);
		}
		UpdateExertion(localPlayer);
		UpdateVisualMotion(localPlayer);
		UpdateHeartbeatAudio(localPlayer);
	}

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

	private void BindConfig()
	{
		//IL_0803: Unknown result type (might be due to invalid IL or missing references)
		//IL_0826: Unknown result type (might be due to invalid IL or missing references)
		//IL_0830: Expected O, but got Unknown
		//IL_0830: 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>("General", "DiagnosticKey", (KeyCode)289, "Writes movement, exertion, terrain, weather and compatibility diagnostics to BepInEx/LogOutput.log.");
		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.");
		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 that triggers a hard fatigue recovery state after a hard run. This begins before literal zero so exhaustion is noticeable and reliable.");
		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.");
		enableSprintFovBoost = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnableSprintFovBoost", true, "Adds a very small field-of-view increase at a fresh full sprint. This stays subtle and fades as heavy exertion takes over.");
		sprintFovBoostDegrees = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "SprintFovBoostDegrees", 2.35f, "Maximum extra FOV at a fresh full sprint. Keep this around 2-3 degrees for a realistic speed feeling rather than an arcade effect.");
		sprintFovBoostSmoothingSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "SprintFovBoostSmoothingSeconds", 0.34f, "How smoothly the sprint FOV expands and relaxes. Slightly slower values feel more physical.");
		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.");
	}

	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 InstallPatches()
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Expected O, but got Unknown
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Expected O, but got Unknown
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Expected O, but got Unknown
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Expected O, but got Unknown
		//IL_0116: Unknown result type (might be due to invalid IL or missing references)
		//IL_012b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0140: Unknown result type (might be due to invalid IL or missing references)
		//IL_014f: Expected O, but got Unknown
		//IL_014f: Expected O, but got Unknown
		//IL_014f: Expected O, but got Unknown
		//IL_0164: Unknown result type (might be due to invalid IL or missing references)
		//IL_016a: Expected O, but got Unknown
		//IL_0210: Unknown result type (might be due to invalid IL or missing references)
		//IL_0220: Expected O, but got Unknown
		harmony = new Harmony("com.marccunningham.survivalmovementexertion");
		setControlsPatchInstalled = TryPatch(FindMethod(typeof(Player), "SetControls", null), new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerSetControlsPrefix", (Type[])null), null, null, "Player.SetControls(...)");
		jogSpeedPatchInstalled = TryPatch(FindMethod(typeof(Player), "GetJogSpeedFactor", Type.EmptyTypes), null, new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerGetJogSpeedFactorPostfix", (Type[])null), null, "Player.GetJogSpeedFactor()");
		runSpeedPatchInstalled = TryPatch(FindMethod(typeof(Player), "GetRunSpeedFactor", Type.EmptyTypes), null, new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerGetRunSpeedFactorPostfix", (Type[])null), null, "Player.GetRunSpeedFactor()");
		checkRunPatchInstalled = TryPatch(FindMethod(typeof(Player), "CheckRun", new Type[2]
		{
			typeof(Vector3),
			typeof(float)
		}), new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerCheckRunPrefix", (Type[])null), new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerCheckRunPostfix", (Type[])null), new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerCheckRunFinalizer", (Type[])null), "Player.CheckRun(Vector3, float)");
		HarmonyMethod val = new HarmonyMethod(typeof(SurvivalMovementPatches), "GameCameraGetCameraPositionPostfix", (Type[])null);
		val.priority = 0;
		val.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, val, 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()");
	}

	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);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Realistic Running: patched " + targetName + "."));
			return true;
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Realistic Running: failed to patch " + targetName + ": " + ex));
			return 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()
	{
		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));
		exhaustedJogRemaining = 0f;
		fatigueRecoveryActive = false;
		wasSprinting = false;
		lastRunDrainMultiplier = 1f;
		smoothedCameraSwayVertical = 0f;
		smoothedCameraSwaySide = 0f;
		cameraSwayVerticalVelocity = 0f;
		cameraSwaySideVelocity = 0f;
		latestCameraDistance = float.MaxValue;
		latestCameraMinimumDistance = float.MaxValue;
		smoothedSprintFovBoost = 0f;
		sprintFovBoostVelocity = 0f;
		if ((Object)(object)Camera.main != (Object)null && baseCameraFieldOfView > 0f)
		{
			Camera.main.fieldOfView = baseCameraFieldOfView;
		}
		baseCameraFieldOfView = -1f;
		heartbeatCurrentPressure = 0f;
		heartbeatPressureVelocity = 0f;
		heartbeatCurrentBpm = 0f;
		heartbeatNextBeatTime = Time.unscaledTime + 0.1f;
		StopHeartbeatAudio();
		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_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0122: Unknown result type (might be due to invalid IL or missing references)
		//IL_0123: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_0151: Unknown result type (might be due to invalid IL or missing references)
		//IL_0156: Unknown result type (might be due to invalid IL or missing references)
		terrainSpeedMultiplier = 1f;
		terrainDrainMultiplier = 1f;
		terrainExertionMultiplier = 1f;
		cachedSlopeAngle = 0f;
		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);
		float num = Mathf.Clamp(hillGraceAngle.Value, 0f, 60f);
		float num2 = Mathf.Max(num + 0.01f, hillFullPenaltyAngle.Value);
		float num3 = Mathf.Clamp01((cachedSlopeAngle - num) / (num2 - num));
		if (num3 <= 0f)
		{
			return;
		}
		Vector3 val = Vector3.ProjectOnPlane(Vector3.up, lastGroundNormal);
		if (!(((Vector3)(ref val)).sqrMagnitude <= 0.0001f))
		{
			((Vector3)(ref val)).Normalize();
			float num4 = Vector3.Dot(((Vector3)(ref moveDir)).normalized, val);
			if (num4 > 0f)
			{
				float num5 = num3 * Mathf.Clamp01(num4);
				terrainSpeedMultiplier = 1f - Mathf.Clamp01(uphillSpeedPenalty.Value) * num5;
				terrainDrainMultiplier = Mathf.Lerp(1f, Mathf.Max(1f, uphillDrainMultiplier.Value), num5);
				terrainExertionMultiplier = Mathf.Lerp(1f, Mathf.Max(1f, uphillExertionMultiplier.Value), num5);
			}
			else if (num4 < 0f)
			{
				float num6 = num3 * Mathf.Clamp01(0f - num4);
				terrainSpeedMultiplier = 1f + Mathf.Clamp(downhillSpeedBonus.Value, 0f, 0.15f) * num6;
				terrainDrainMultiplier = Mathf.Lerp(1f, Mathf.Clamp(1f - downhillDrainReduction.Value, 0.65f, 1f), num6);
			}
		}
	}

	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 UpdateHeartbeatAudio(Player player)
	{
		if (!enableExhaustionHeartbeat.Value || (Object)(object)heartbeatAudioSource == (Object)null || heartbeatClip == (Object)null || heartbeatPlayOneShotMethod == null)
		{
			return;
		}
		float heartbeatPressure = GetHeartbeatPressure(player);
		float num = Mathf.Max(0.05f, heartbeatIntensitySmoothingSeconds.Value);
		heartbeatCurrentPressure = Mathf.SmoothDamp(heartbeatCurrentPressure, heartbeatPressure, ref heartbeatPressureVelocity, num, float.PositiveInfinity, Time.deltaTime);
		if (heartbeatCurrentPressure <= 0.002f)
		{
			heartbeatCurrentBpm = 0f;
			heartbeatNextBeatTime = Time.unscaledTime + 0.1f;
			return;
		}
		float num2 = Mathf.Clamp(heartbeatRecoveryBpm.Value, 45f, 120f);
		float num3 = Mathf.Clamp(heartbeatMaximumBpm.Value, num2 + 1f, 180f);
		heartbeatCurrentBpm = Mathf.Lerp(num2, num3, SmoothStep01(heartbeatCurrentPressure));
		float num4 = 60f / Mathf.Max(1f, heartbeatCurrentBpm);
		if (Time.unscaledTime < heartbeatNextBeatTime)
		{
			return;
		}
		float num5 = Mathf.Clamp01(heartbeatMaximumVolume.Value) * Mathf.Lerp(0.26f, 1f, heartbeatCurrentPressure);
		try
		{
			heartbeatPlayOneShotMethod.Invoke(heartbeatAudioSource, new object[2] { heartbeatClip, num5 });
			heartbeatNextBeatTime = Time.unscaledTime + num4;
		}
		catch (Exception ex)
		{
			heartbeatStatus = "playback exception: " + ex.GetType().Name;
			heartbeatNextBeatTime = Time.unscaledTime + 1f;
		}
	}

	private float GetHeartbeatPressure(Player player)
	{
		if (!IsMovementEligible(player))
		{
			return 0f;
		}
		float num = Mathf.Clamp(tunnelVisionStartExertion.Value, 0f, 95f);
		float num2 = Mathf.Clamp(tunnelVisionFullExertion.Value, num + 0.1f, 100f);
		float num3 = SmoothStep01(Mathf.InverseLerp(num, num2, exertion));
		float num4 = Mathf.Clamp01(((Character)player).GetStaminaPercentage());
		float num5 = 1f - Mathf.InverseLerp(0.08f, 0.52f, num4);
		float num6 = Mathf.Max(num3, num5 * 0.7f);
		if (fatigueRecoveryActive)
		{
			float num7 = Mathf.Max(0.1f, exhaustedJogSeconds.Value);
			float num8 = Mathf.Clamp01(exhaustedJogRemaining / num7);
			float num9 = Mathf.Lerp(0.34f, 1f, num8);
			num6 = Mathf.Max(num6, num9);
		}
		float num10 = Mathf.Clamp01(heartbeatStartPressure.Value);
		return SmoothStep01(Mathf.InverseLerp(num10, 1f, num6));
	}

	private void StopHeartbeatAudio()
	{
		if ((Object)(object)heartbeatAudioSource == (Object)null || heartbeatStopMethod == null)
		{
			return;
		}
		try
		{
			heartbeatStopMethod.Invoke(heartbeatAudioSource, null);
		}
		catch
		{
		}
	}

	private static Type FindLoadedType(string fullName)
	{
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		for (int i = 0; i < assemblies.Length; i++)
		{
			Type type = assemblies[i].GetType(fullName, throwOnError: false);
			if (type != null)
			{
				return type;
			}
		}
		return null;
	}

	private static void SetNumericProperty(Type type, object instance, string name, float value)
	{
		PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public);
		if (property != null && property.CanWrite)
		{
			property.SetValue(instance, value, null);
		}
	}

	private static void SetBooleanProperty(Type type, object instance, string name, bool value)
	{
		PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public);
		if (property != null && property.CanWrite)
		{
			property.SetValue(instance, value, null);
		}
	}

	private static bool TryReadWaveFile(string path, out float[] samples, out int channels, out int sampleRate, out string status)
	{
		samples = null;
		channels = 0;
		sampleRate = 0;
		status = "unknown error";
		try
		{
			byte[] array = File.ReadAllBytes(path);
			if (array.Length < 44 || ReadAscii(array, 0, 4) != "RIFF" || ReadAscii(array, 8, 4) != "WAVE")
			{
				status = "not a RIFF/WAVE file";
				return false;
			}
			int num = 0;
			int num2 = 0;
			int num3 = -1;
			int num4 = 0;
			int num5 = 12;
			while (num5 + 8 <= array.Length)
			{
				string text = ReadAscii(array, num5, 4);
				int num6 = ReadInt32LittleEndian(array, num5 + 4);
				int num7 = num5 + 8;
				if (num6 < 0 || num7 + num6 > array.Length)
				{
					status = "invalid WAV chunk length";
					return false;
				}
				if (text == "fmt " && num6 >= 16)
				{
					num = ReadUInt16LittleEndian(array, num7);
					channels = ReadUInt16LittleEndian(array, num7 + 2);
					sampleRate = ReadInt32LittleEndian(array, num7 + 4);
					num2 = ReadUInt16LittleEndian(array, num7 + 14);
				}
				else if (text == "data")
				{
					num3 = num7;
					num4 = num6;
				}
				num5 = num7 + num6 + num6 % 2;
			}
			if (channels < 1 || channels > 2 || sampleRate < 8000 || num3 < 0 || num4 <= 0)
			{
				status = "missing supported WAV format or data chunk";
				return false;
			}
			if (num != 1 && num != 3)
			{
				status = "unsupported WAV encoding " + num;
				return false;
			}
			int num8 = num2 / 8;
			if (num8 < 1 || num8 > 4 || num4 % (channels * num8) != 0)
			{
				status = "unsupported sample layout";
				return false;
			}
			int num9 = num4 / num8;
			samples = new float[num9];
			int num10 = num3;
			for (int i = 0; i < num9; i++)
			{
				if (num == 3 && num2 == 32)
				{
					samples[i] = BitConverter.ToSingle(array, num10);
				}
				else
				{
					switch (num2)
					{
					case 8:
						samples[i] = (float)(array[num10] - 128) / 128f;
						break;
					case 16:
						samples[i] = (float)(short)ReadUInt16LittleEndian(array, num10) / 32768f;
						break;
					case 24:
					{
						int num11 = array[num10] | (array[num10 + 1] << 8) | (array[num10 + 2] << 16);
						if ((num11 & 0x800000) != 0)
						{
							num11 |= -16777216;
						}
						samples[i] = (float)num11 / 8388608f;
						break;
					}
					case 32:
						samples[i] = (float)ReadInt32LittleEndian(array, num10) / 2.1474836E+09f;
						break;
					default:
						status = "unsupported bit depth " + num2;
						samples = null;
						return false;
					}
				}
				num10 += num8;
			}
			status = "decoded";
			return true;
		}
		catch (Exception ex)
		{
			status = ex.GetType().Name;
			samples = null;
			return false;
		}
	}

	private static string ReadAscii(byte[] bytes, int start, int length)
	{
		char[] array = new char[length];
		for (int i = 0; i < length; i++)
		{
			array[i] = (char)bytes[start + i];
		}
		return new string(array);
	}

	private static int ReadInt32LittleEndian(byte[] bytes, int start)
	{
		return bytes[start] | (bytes[start + 1] << 8) | (bytes[start + 2] << 16) | (bytes[start + 3] << 24);
	}

	private static int ReadUInt16LittleEndian(byte[] bytes, int start)
	{
		return bytes[start] | (bytes[start + 1] << 8);
	}

	private void UpdateExertion(Player player)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		Vector3 moveDir = ((Character)player).GetMoveDir();
		moveDir.y = 0f;
		bool flag = ((Vector3)(ref moveDir)).sqrMagnitude > 1.0000001E-06f;
		bool flag2 = ((Character)player).IsRunning() && flag && !ShouldForceExhaustedJog(player);
		float deltaTime = Time.deltaTime;
		if (flag2)
		{
			float exertionGainMultiplier = SurvivalMovementExertionBridge.GetExertionGainMultiplier(player);
			float num = terrainExertionMultiplier * weatherExertionMultiplier * injuryExertionMultiplier * exertionGainMultiplier;
			exertion = Mathf.Clamp(exertion + Mathf.Max(0f, exertionGainPerSecond.Value) * num * deltaTime, 0f, 100f);
			sprintBuild = Mathf.MoveTowards(sprintBuild, 1f, deltaTime / Mathf.Max(0.01f, sprintBuildUpSeconds.Value));
		}
		else
		{
			float num2 = Mathf.Max(0f, exertionRecoveryPerSecond.Value) * weatherRecoveryMultiplier * SurvivalMovementExertionBridge.GetRecoveryMultiplier(player);
			if (!flag)
			{
				num2 *= Mathf.Max(1f, stationaryRecoveryMultiplier.Value);
			}
			exertion = Mathf.MoveTowards(exertion, 0f, num2 * deltaTime);
			sprintBuild = Mathf.MoveTowards(sprintBuild, 0f, deltaTime / Mathf.Max(0.01f, sprintBuildRecoverySeconds.Value));
		}
		float num3 = Mathf.Clamp01(((Character)player).GetStaminaPercentage());
		float num4 = Mathf.Clamp(exhaustionTriggerStaminaPercentage.Value, 0f, 0.25f);
		if ((flag2 || wasSprinting || sprintBuild > 0.2f) && num3 <= num4)
		{
			fatigueRecoveryActive = true;
			exhaustedJogRemaining = Mathf.Max(exhaustedJogRemaining, Mathf.Max(0f, exhaustedJogSeconds.Value));
		}
		if (exhaustedJogRemaining > 0f)
		{
			exhaustedJogRemaining = Mathf.Max(0f, exhaustedJogRemaining - deltaTime);
		}
		if (fatigueRecoveryActive && exhaustedJogRemaining <= 0f)
		{
			float num5 = Mathf.Clamp(recoveryStaminaPercentage.Value, 0.05f, 1f);
			float num6 = Mathf.Clamp(recoveryExertionPercentage.Value, 0f, 100f);
			if (num3 >= num5 && exertion <= num6)
			{
				fatigueRecoveryActive = false;
			}
		}
		wasSprinting = flag2;
	}

	internal void RecordSetControlsHook()
	{
		setControlsHookCalls++;
	}

	internal void RecordJogSpeedHook()
	{
		jogSpeedHookCalls++;
	}

	internal void RecordRunSpeedHook()
	{
		runSpeedHookCalls++;
	}

	internal void RecordCheckRunHook()
	{
		checkRunHookCalls++;
	}

	internal void RecordCameraHook()
	{
		cameraHookCalls++;
	}

	internal Vector3 SmoothMoveInput(Player player, Vector3 rawMoveDirection)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		if (!IsMovementEligible(player) || !enableInputSmoothing.Value)
		{
			return rawMoveDirection;
		}
		float num = Mathf.Clamp01(((Vector3)(ref rawMoveDirection)).magnitude);
		float num2 = ((num > smoothedInputMagnitude) ? Mathf.Max(0.01f, accelerationSeconds.Value) : Mathf.Max(0.01f, decelerationSeconds.Value));
		smoothedInputMagnitude = Mathf.MoveTowards(smoothedInputMagnitude, num, Time.deltaTime / num2);
		if (num <= 0.001f)
		{
			return Vector3.zero;
		}
		return ((Vector3)(ref rawMoveDirection)).normalized * Mathf.Clamp01(smoothedInputMagnitude);
	}

	internal float GetJogSpeedMultiplier(Player player)
	{
		if (!IsMovementEligible(player))
		{
			return 1f;
		}
		float directionalSpeedMultiplier = GetDirectionalSpeedMultiplier(player);
		directionalSpeedMultiplier *= GetWorldMovementMultiplier(player);
		if (ShouldForceExhaustedJog(player))
		{
			directionalSpeedMultiplier *= Mathf.Clamp(exhaustedJogSpeedMultiplier.Value, 0.35f, 1f);
		}
		return Mathf.Clamp(directionalSpeedMultiplier, 0.2f, 1.35f);
	}

	internal float GetRunSpeedMultiplier(Player player)
	{
		if (!IsMovementEligible(player))
		{
			return 1f;
		}
		if (ShouldForceExhaustedJog(player))
		{
			return GetJogSpeedMultiplier(player);
		}
		float num = Mathf.Clamp(topSprintSpeedMultiplier.Value, 0.8f, 1.65f);
		float num2 = Mathf.Clamp(sprintStartSpeedFraction.Value, 0.35f, 1f);
		float num3 = Mathf.Lerp(num * num2, num, Mathf.Clamp01(sprintBuild));
		float num4 = Mathf.Lerp(1f, Mathf.Clamp(highExertionRunSpeedMultiplier.Value, 0.5f, 1f), GetHighExertionFraction());
		float directionalSpeedMultiplier = GetDirectionalSpeedMultiplier(player);
		directionalSpeedMultiplier *= num3;
		directionalSpeedMultiplier *= num4;
		directionalSpeedMultiplier *= GetWorldMovementMultiplier(player);
		return Mathf.Clamp(directionalSpeedMultiplier, 0.2f, 1.65f);
	}

	private float GetWorldMovementMultiplier(Player player)
	{
		float num = terrainSpeedMultiplier * weatherSpeedMultiplier * injurySpeedMultiplier;
		num *= SurvivalMovementExertionBridge.GetMovementMultiplier(player);
		return Mathf.Clamp(num, 0.2f, 1.35f);
	}

	internal bool PrepareCheckRun(Player player, ref float nativeRunStaminaDrain, ref bool result, ref RunDrainPatchState state)
	{
		state = default(RunDrainPatchState);
		RecordCheckRunHook();
		if (!IsMovementEligible(player))
		{
			return true;
		}
		if (ShouldForceExhaustedJog(player))
		{
			result = false;
			return false;
		}
		state.RestoreDrain = true;
		state.OriginalDrain = nativeRunStaminaDrain;
		nativeRunStaminaDrain *= GetRunStaminaDrainMultiplier(player);
		return true;
	}

	internal void RestoreCheckRunDrain(ref float nativeRunStaminaDrain, RunDrainPatchState state)
	{
		if (state.RestoreDrain)
		{
			nativeRunStaminaDrain = state.OriginalDrain;
		}
	}

	private float GetRunStaminaDrainMultiplier(Player player)
	{
		float num = Mathf.Clamp(baseRunStaminaDrainMultiplier.Value, 0.02f, 2f);
		float num2 = Mathf.Lerp(1f, Mathf.Clamp(highExertionDrainMultiplier.Value, 1f, 4f), GetHighExertionFraction());
		float runDrainMultiplier = SurvivalMovementExertionBridge.GetRunDrainMultiplier(player);
		lastRunDrainMultiplier = num * num2 * terrainDrainMultiplier * weatherDrainMultiplier * runDrainMultiplier;
		float num3 = Mathf.Clamp(maximumCombinedRunDrainMultiplier.Value, 0.25f, 8f);
		return Mathf.Clamp(lastRunDrainMultiplier, 0.01f, num3);
	}

	private bool ShouldForceExhaustedJog(Player player)
	{
		if (!IsMovementEligible(player) || !fatigueRecoveryActive)
		{
			return false;
		}
		if (exhaustedJogRemaining > 0f)
		{
			return true;
		}
		float num = Mathf.Clamp(emergencySprintReleaseStaminaPercentage.Value, 0.05f, 0.6f);
		return ((Character)player).GetStaminaPercentage() < num;
	}

	private float GetDirectionalSpeedMultiplier(Player player)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		Vector3 moveDir = ((Character)player).GetMoveDir();
		moveDir.y = 0f;
		if (((Vector3)(ref moveDir)).sqrMagnitude <= 1.0000001E-06f)
		{
			return 1f;
		}
		Vector3 val = ((Component)player).transform.InverseTransformDirection(((Vector3)(ref moveDir)).normalized);
		float num = Mathf.Max(0f, val.z);
		float num2 = Mathf.Max(0f, 0f - val.z);
		float num3 = Mathf.Abs(val.x);
		float num4 = num + num2 + num3;
		if (num4 <= 0.001f)
		{
			return 1f;
		}
		float num5 = Mathf.Clamp(backwardSpeedMultiplier.Value, 0.35f, 1f);
		float num6 = Mathf.Clamp(sidewaysSpeedMultiplier.Value, 0.35f, 1f);
		float num7 = num * 1f + num2 * num5 + num3 * num6;
		return num7 / num4;
	}

	private float GetHighExertionFraction()
	{
		float num = Mathf.Clamp(highExertionStart.Value, 1f, 99f);
		return Mathf.Clamp01((exertion - num) / (100f - num));
	}

	private float GetVisualIntensity(Player player)
	{
		if (!IsMovementEligible(player))
		{
			return 0f;
		}
		float num = Mathf.Clamp(tunnelVisionStartExertion.Value, 0f, 95f);
		float num2 = Mathf.Clamp(tunnelVisionFullExertion.Value, num + 0.1f, 100f);
		float value = Mathf.InverseLerp(num, num2, exertion);
		float num3 = SmoothStep01(value);
		float num4 = Mathf.Clamp01(((Character)player).GetStaminaPercentage());
		float num5 = 1f - Mathf.InverseLerp(0.05f, 0.42f, num4);
		float num6 = (fatigueRecoveryActive ? 1f : 0f);
		return Mathf.Clamp01(Mathf.Max(new float[3]
		{
			num3,
			num5 * 0.6f,
			num6 * 0.96f
		}));
	}

	private static float SmoothStep01(float value)
	{
		value = Mathf.Clamp01(value);
		return value * value * (3f - 2f * value);
	}

	private void UpdateVisualMotion(Player player)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		if (!enableCameraSway.Value || !IsMovementEligible(player))
		{
			SmoothCameraSwayToward(0f, 0f);
			return;
		}
		Vector3 moveDir = ((Character)player).GetMoveDir();
		moveDir.y = 0f;
		bool flag = ((Vector3)(ref moveDir)).sqrMagnitude > 1.0000001E-06f;
		float visualIntensity = GetVisualIntensity(player);
		Vector3 velocity = ((Character)player).GetVelocity();
		velocity.y = 0f;
		float magnitude = ((Vector3)(ref velocity)).magnitude;
		float num = Mathf.Clamp01(magnitude / Mathf.Max(0.1f, 10f * Mathf.Max(1f, topSprintSpeedMultiplier.Value)));
		float num2 = ((((Character)player).IsRunning() && flag && !ShouldForceExhaustedJog(player)) ? Mathf.Clamp01(num * 0.65f + Mathf.Clamp01(sprintBuild) * 0.35f) : 0f);
		float num3 = Mathf.Lerp(Mathf.Clamp(sprintSwayFrequencyLow.Value, 0.2f, 4f), Mathf.Clamp(sprintSwayFrequencyHigh.Value, 0.2f, 4f), num2);
		float num4 = Mathf.Lerp(Mathf.Clamp(breathSwayFrequencyLow.Value, 0.05f, 1.5f), Mathf.Clamp(breathSwayFrequencyHigh.Value, 0.05f, 1.5f), visualIntensity);
		float num5 = Time.time * (float)Math.PI * 2f * num3;
		float num6 = Time.time * (float)Math.PI * 2f * num4;
		float num7 = Mathf.Sin(num5) * 0.66f + Mathf.Sin(num5 * 2f + 0.55f) * 0.09f;
		float num8 = Mathf.Sin(num5 * 0.5f + 0.35f);
		float num9 = Mathf.Sin(num6);
		float targetVertical = num7 * Mathf.Max(0f, sprintBobVerticalMeters.Value) * num2 + num9 * Mathf.Max(0f, fatigueBreathSwayMeters.Value) * visualIntensity;
		float targetSide = num8 * Mathf.Max(0f, sprintBobSideMeters.Value) * num2 * 0.85f;
		SmoothCameraSwayToward(targetVertical, targetSide);
	}

	private void SmoothCameraSwayToward(float targetVertical, float targetSide)
	{
		float num = Mathf.Max(0.03f, cameraSwaySmoothingSeconds.Value);
		smoothedCameraSwayVertical = Mathf.SmoothDamp(smoothedCameraSwayVertical, targetVertical, ref cameraSwayVerticalVelocity, num, float.PositiveInfinity, Time.deltaTime);
		smoothedCameraSwaySide = Mathf.SmoothDamp(smoothedCameraSwaySide, targetSide, ref cameraSwaySideVelocity, num, float.PositiveInfinity, Time.deltaTime);
	}

	internal void ApplyCameraSway(Player player, GameCamera camera, ref Vector3 position, float distance, float minimumDistance)
	{
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		RecordCameraHook();
		latestCameraDistance = distance;
		latestCameraMinimumDistance = minimumDistance;
		ApplySprintFov(player, camera, distance, minimumDistance);
		if (enableCameraSway.Value && IsMovementEligible(player) && !((Object)(object)camera == (Object)null) && (!cameraSwayClosestZoomOnly.Value || !(distance > minimumDistance + Mathf.Max(0f, closestZoomTolerance.Value))) && (!(Mathf.Abs(smoothedCameraSwayVertical) <= 1E-05f) || !(Mathf.Abs(smoothedCameraSwaySide) <= 1E-05f)))
		{
			position += ((Component)camera).transform.right * smoothedCameraSwaySide;
			position += Vector3.up * smoothedCameraSwayVertical;
		}
	}

	private void ApplySprintFov(Player player, GameCamera camera, float distance, float minimumDistance)
	{
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		Camera main = Camera.main;
		if (!((Object)(object)main == (Object)null))
		{
			if (baseCameraFieldOfView <= 0f)
			{
				baseCameraFieldOfView = main.fieldOfView;
			}
			float num = 0f;
			bool flag = !cameraSwayClosestZoomOnly.Value || distance <= minimumDistance + Mathf.Max(0f, closestZoomTolerance.Value);
			if (enableSprintFovBoost.Value && IsMovementEligible(player) && flag)
			{
				Vector3 velocity = ((Character)player).GetVelocity();
				velocity.y = 0f;
				float magnitude = ((Vector3)(ref velocity)).magnitude;
				float value = Mathf.Clamp01(magnitude / Mathf.Max(0.1f, 10f * Mathf.Max(1f, topSprintSpeedMultiplier.Value)));
				float num2 = Mathf.Clamp01(sprintBuild);
				float num3 = 1f - Mathf.Clamp01(GetHighExertionFraction() * 0.85f + (fatigueRecoveryActive ? 0.25f : 0f));
				num = Mathf.Max(0f, sprintFovBoostDegrees.Value) * SmoothStep01(value) * Mathf.Lerp(0.45f, 1f, num2) * num3;
			}
			float num4 = Mathf.Max(0.05f, sprintFovBoostSmoothingSeconds.Value);
			smoothedSprintFovBoost = Mathf.SmoothDamp(smoothedSprintFovBoost, num, ref sprintFovBoostVelocity, num4, float.PositiveInfinity, Time.deltaTime);
			main.fieldOfView = baseCameraFieldOfView + smoothedSprintFovBoost;
		}
	}

	private void DrawWindRush(Player player)
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0143: Unknown result type (might be due to invalid IL or missing references)
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		//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_032f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0337: Unknown result type (might be due to invalid IL or missing references)
		//IL_022a: Unknown result type (might be due to invalid IL or missing references)
		//IL_022c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_025a: Unknown result type (might be due to invalid IL or missing references)
		//IL_025f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0264: Unknown result type (might be due to invalid IL or missing references)
		//IL_029f: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_0303: Unknown result type (might be due to invalid IL or missing references)
		if (!enableWindRushStreaks.Value || !IsMovementEligible(player))
		{
			return;
		}
		Vector3 moveDir = ((Character)player).GetMoveDir();
		moveDir.y = 0f;
		if (!((Character)player).IsRunning() || ((Vector3)(ref moveDir)).sqrMagnitude <= 1.0000001E-06f || ShouldForceExhaustedJog(player))
		{
			return;
		}
		float num = Mathf.Clamp(windRushStartSprintBuild.Value, 0f, 0.95f);
		float num2 = Mathf.InverseLerp(num, 1f, Mathf.Clamp01(sprintBuild));
		if (num2 <= 0.005f)
		{
			return;
		}
		EnsureWindStreaks();
		if (windStreaks == null || windStreaks.Length == 0)
		{
			return;
		}
		float num3 = Mathf.Lerp(1f, 0.66f, GetHighExertionFraction());
		float num4 = Mathf.Clamp(windRushMaximumAlpha.Value, 0.05f, 0.65f) * num2 * num3;
		float num5 = Mathf.Max(0.1f, windRushTravelSpeed.Value);
		Vector2 val = default(Vector2);
		((Vector2)(ref val))..ctor((float)Screen.width * 0.5f, (float)Screen.height * 0.5f);
		Matrix4x4 matrix = GUI.matrix;
		Color color = GUI.color;
		Vector2 val2 = default(Vector2);
		for (int i = 0; i < windStreaks.Length; i++)
		{
			WindStreak windStreak = windStreaks[i];
			float num6 = Mathf.Repeat(Time.time * num5 * windStreak.Speed + windStreak.Phase, 1f);
			float num7 = SmoothStep01(num6);
			float num8 = SmoothStep01(Mathf.InverseLerp(0f, 0.13f, num6));
			float num9 = 1f - SmoothStep01(Mathf.InverseLerp(0.68f, 1f, num6));
			float num10 = num4 * windStreak.Alpha * num8 * num9;
			if (!(num10 <= 0.002f))
			{
				float num11 = Mathf.Lerp(windStreak.InnerRadius, 1.18f, num7);
				((Vector2)(ref val2))..ctor(Mathf.Cos(windStreak.AngleRadians), Mathf.Sin(windStreak.AngleRadians));
				Vector2 val3 = val + new Vector2(val2.x * (float)Screen.width * 0.5f * num11, val2.y * (float)Screen.height * 0.5f * num11);
				float num12 = Mathf.Lerp(22f, (float)Mathf.Max(Screen.width, Screen.height) * windStreak.Length, num7);
				float num13 = Mathf.Lerp(0.8f, 2.2f, num7);
				float num14 = Mathf.Atan2(val2.y, val2.x) * 57.29578f;
				GUI.matrix = matrix;
				GUIUtility.RotateAroundPivot(num14, val3);
				GUI.color = new Color(0.7f, 0.84f, 0.96f, num10);
				GUI.DrawTexture(new Rect(val3.x, val3.y - num13 * 0.5f, num12, num13), (Texture)(object)Texture2D.whiteTexture);
			}
		}
		GUI.matrix = matrix;
		GUI.color = color;
	}

	private void EnsureWindStreaks()
	{
		int num = Mathf.Clamp(windRushStreakCount.Value, 4, 48);
		if (windStreaks == null || windStreaks.Length != num)
		{
			windStreaks = new WindStreak[num];
			for (int i = 0; i < num; i++)
			{
				float num2 = PseudoRandom01(i + 11);
				float num3 = PseudoRandom01(i + 37);
				float phase = PseudoRandom01(i + 73);
				float num4 = PseudoRandom01(i + 101);
				float num5 = PseudoRandom01(i + 149);
				float num6 = (float)i / (float)num * (float)Math.PI * 2f;
				float angleRadians = num6 + Mathf.Lerp(-0.12f, 0.12f, num2);
				windStreaks[i] = new WindStreak(angleRadians, Mathf.Lerp(0.28f, 0.48f, num3), phase, Mathf.Lerp(0.72f, 1.4f, num4), Mathf.Lerp(0.055f, 0.16f, num5), Mathf.Lerp(0.4f, 1f, PseudoRandom01(i + 197)));
			}
		}
	}

	private static float PseudoRandom01(int value)
	{
		float num = Mathf.Sin((float)value * 12.9898f) * 43758.547f;
		return num - Mathf.Floor(num);
	}

	private void DrawPeripheralBlur(Player player)
	{
		//IL_0126: Unknown result type (might be due to invalid IL or missing references)
		//IL_012b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0143: Unknown result type (might be due to invalid IL or missing references)
		//IL_0164: Unknown result type (might be due to invalid IL or missing references)
		//IL_0177: Unknown result type (might be due to invalid IL or missing references)
		if (!enablePeripheralBlurOverlay.Value)
		{
			return;
		}
		float visualIntensity = GetVisualIntensity(player);
		float num = Mathf.Clamp01(peripheralBlurStartIntensity.Value);
		float value = Mathf.InverseLerp(num, 1f, visualIntensity);
		value = SmoothStep01(value);
		if (!(value <= 0.003f))
		{
			EnsurePeripheralBlurTextures();
			if (peripheralBlurTextures != null && peripheralBlurTextures.Length != 0)
			{
				int num2 = Mathf.Clamp(Mathf.RoundToInt(value * (float)(peripheralBlurTextures.Length - 1)), 0, peripheralBlurTextures.Length - 1);
				float num3 = Mathf.Clamp(peripheralBlurMaximumAlpha.Value, 0f, 0.45f) * Mathf.Lerp(0.12f, 1f, value);
				float num4 = Mathf.Lerp(0.18f, 0.42f, value);
				float num5 = 0.5f + 0.5f * Mathf.Sin(Time.time * (float)Math.PI * 2f * num4);
				num3 *= Mathf.Lerp(0.96f, 1.06f, num5);
				Color color = GUI.color;
				GUI.color = new Color(0.92f, 0.95f, 1f, Mathf.Clamp01(num3));
				GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)peripheralBlurTextures[num2]);
				GUI.color = color;
			}
		}
	}

	private void DrawTunnelVision(Player player)
	{
		//IL_0142: Unknown result type (might be due to invalid IL or missing references)
		//IL_0147: Unknown result type (might be due to invalid IL or missing references)
		//IL_015f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0180: Unknown result type (might be due to invalid IL or missing references)
		//IL_0194: Unknown result type (might be due to invalid IL or missing references)
		if (!enableTunnelVision.Value)
		{
			return;
		}
		float visualIntensity = GetVisualIntensity(player);
		if (!(visualIntensity <= 0.005f))
		{
			EnsureTunnelTextures();
			if (tunnelTextures != null && tunnelTextures.Length != 0)
			{
				float num = Mathf.Clamp01(tunnelVisionPulseStrength.Value) * visualIntensity;
				float num2 = Mathf.Lerp(0.2f, 0.48f, visualIntensity);
				float num3 = 0.5f + 0.5f * Mathf.Sin(Time.time * (float)Math.PI * 2f * num2);
				float num4 = (num3 - 0.5f) * num * 0.16f;
				float num5 = Mathf.Clamp01(visualIntensity + num4);
				int num6 = Mathf.Clamp(Mathf.RoundToInt(num5 * (float)(tunnelTextures.Length - 1)), 0, tunnelTextures.Length - 1);
				float num7 = Mathf.Clamp(maximumTunnelVisionAlpha.Value, 0f, 0.82f);
				float num8 = num7 * Mathf.Lerp(0.08f, 1f, visualIntensity);
				num8 *= Mathf.Lerp(1f - num * 0.1f, 1f + num * 0.1f, num3);
				Color color = GUI.color;
				GUI.color = new Color(1f, 1f, 1f, Mathf.Clamp01(num8));
				GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)tunnelTextures[num6]);
				GUI.color = color;
			}
		}
	}

	private void EnsurePeripheralBlurTextures()
	{
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01df: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e6: Expected O, but got Unknown
		//IL_0180: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: Unknown result type (might be due to invalid IL or missing references)
		//IL_018e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		if (peripheralBlurTextures != null)
		{
			return;
		}
		peripheralBlurTextures = (Texture2D[])(object)new Texture2D[18];
		Color val = default(Color);
		Color val2 = default(Color);
		for (int i = 0; i < 18; i++)
		{
			float value = (float)i / 17f;
			float num = SmoothStep01(value);
			float num2 = Mathf.Clamp(peripheralBlurClearRadiusAtExhaustion.Value, 0.72f, 1.1f);
			float num3 = Mathf.Lerp(1.22f, num2, num);
			float num4 = Mathf.Lerp(0.68f, 0.6f, num);
			float num5 = Mathf.Max(0f, num3 - num4);
			((Color)(ref val))..ctor(0.82f, 0.89f, 0.97f, 1f);
			((Color)(ref val2))..ctor(0.34f, 0.42f, 0.52f, 1f);
			Color val3 = Color.Lerp(val, val2, num * 0.55f);
			Color[] array = (Color[])(object)new Color[25600];
			for (int j = 0; j < 160; j++)
			{
				for (int k = 0; k < 160; k++)
				{
					float num6 = ((float)k / 159f - 0.5f) * 2f;
					float num7 = ((float)j / 159f - 0.5f) * 2f;
					float num8 = Mathf.Sqrt(num6 * num6 + num7 * 0.84f * (num7 * 0.84f));
					float value2 = Mathf.Clamp01((num8 - num5) / Mathf.Max(0.001f, num3 - num5));
					value2 = SmoothStep01(value2);
					value2 *= Mathf.Lerp(0.1f, 0.82f, num);
					array[j * 160 + k] = new Color(val3.r, val3.g, val3.b, value2);
				}
			}
			Texture2D val4 = new Texture2D(160, 160, (TextureFormat)4, false);
			((Texture)val4).wrapMode = (TextureWrapMode)1;
			((Texture)val4).filterMode = (FilterMode)1;
			val4.SetPixels(array);
			val4.Apply();
			peripheralBlurTextures[i] = val4;
		}
	}

	private void EnsureTunnelTextures()
	{
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ef: Expected O, but got Unknown
		//IL_0189: Unknown result type (might be due to invalid IL or missing references)
		//IL_0190: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
		if (tunnelTextures != null)
		{
			return;
		}
		tunnelTextures = (Texture2D[])(object)new Texture2D[18];
		Color val = default(Color);
		Color val2 = default(Color);
		for (int i = 0; i < 18; i++)
		{
			float value = (float)i / 17f;
			float num = SmoothStep01(value);
			float num2 = Mathf.Clamp(tunnelVisionClearRadiusAtExhaustion.Value, 0.55f, 1.1f);
			float num3 = Mathf.Lerp(1.2f, num2, num);
			float num4 = Mathf.Lerp(0.64f, 0.56f, num);
			float num5 = Mathf.Max(0f, num3 - num4);
			float num6 = Mathf.Clamp01(coolEdgeTintStrength.Value) * Mathf.Lerp(0.95f, 0.38f, num);
			((Color)(ref val))..ctor(0.13f, 0.23f, 0.34f, 1f);
			((Color)(ref val2))..ctor(0.015f, 0.025f, 0.05f, 1f);
			Color val3 = Color.Lerp(val2, val, num6);
			Color[] array = (Color[])(object)new Color[25600];
			for (int j = 0; j < 160; j++)
			{
				for (int k = 0; k < 160; k++)
				{
					float num7 = ((float)k / 159f - 0.5f) * 2f;
					float num8 = ((float)j / 159f - 0.5f) * 2f;
					float num9 = Mathf.Sqrt(num7 * num7 + num8 * 0.84f * (num8 * 0.84f));
					float value2 = Mathf.Clamp01((num9 - num5) / Mathf.Max(0.001f, num3 - num5));
					value2 = SmoothStep01(value2);
					array[j * 160 + k] = new Color(val3.r, val3.g, val3.b, value2);
				}
			}
			Texture2D val4 = new Texture2D(160, 160, (TextureFormat)4, false);
			((Texture)val4).wrapMode = (TextureWrapMode)1;
			((Texture)val4).filterMode = (FilterMode)1;
			val4.SetPixels(array);
			val4.Apply();
			tunnelTextures[i] = val4;
		}
	}

	internal void ApplyExhaustionDepthOfField(CameraEffects cameraEffects)
	{
		depthOfFieldHookCalls++;
		if (!enableNativeDepthOfField.Value || (Object)(object)cameraEffects == (Object)null)
		{
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		if (!IsMovementEligible(localPlayer) || (depthOfFieldClosestZoomOnly.Value && latestCameraDistance > latestCameraMinimumDistance + Mathf.Max(0f, closestZoomTolerance.Value)))
		{
			return;
		}
		float visualIntensity = GetVisualIntensity(localPlayer);
		float num = Mathf.Clamp(depthOfFieldStartVisualIntensity.Value, 0f, 0.95f);
		float value = Mathf.InverseLerp(num, 1f, visualIntensity);
		value = SmoothStep01(value);
		if (value <= 0.005f || !TryResolveDepthOfField(cameraEffects, out var dof))
		{
			return;
		}
		Behaviour val = (Behaviour)((dof is Behaviour) ? dof : null);
		if ((Object)(object)val != (Object)null)
		{
			val.enabled = true;
		}
		Camera main = Camera.main;
		if ((Object)(object)main == (Object)null)
		{
			depthOfFieldStatus = "native DOF found, Camera.main unavailable";
			return;
		}
		float depthOfFieldFocusDistance = GetDepthOfFieldFocusDistance(main, cameraEffects);
		float value2 = Mathf.Lerp(3.5f, Mathf.Clamp(depthOfFieldFocalSizeAtExhaustion.Value, 0.35f, 8f), value);
		float value3 = Mathf.Lerp(0.1f, Mathf.Clamp(depthOfFieldMaximumBlurSize.Value, 0.1f, 1.25f), value);
		bool flag = false;
		flag |= TrySetNumericMember(dof, dofFocusDistanceMember, depthOfFieldFocusDistance);
		flag |= TrySetNumericMember(dof, dofFocalSizeMember, value2);
		flag |= TrySetNumericMember(dof, dofMaxBlurSizeMember, value3);
		if (dofApertureMember != null)
		{
			flag |= TrySetNumericMember(dof, dofApertureMember, Mathf.Lerp(4.2f, 2.6f, value));
		}
		depthOfFieldStatus = (flag ? ("active " + dof.GetType().FullName) : "native DOF found but recognised focus members were unavailable");
	}

	private bool TryResolveDepthOfField(CameraEffects cameraEffects, out object dof)
	{
		dof = null;
		if (cameraEffectsDofField == null)
		{
			cameraEffectsDofField = typeof(CameraEffects).GetField("m_dof", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			cameraEffectsDofRayMaskField = typeof(CameraEffects).GetField("m_dofRayMask", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		}
		if (cameraEffectsDofField == null)
		{
			depthOfFieldStatus = "CameraEffects.m_dof not found";
			return false;
		}
		dof = cameraEffectsDofField.GetValue(cameraEffects);
		if (dof == null)
		{
			depthOfFieldStatus = "CameraEffects.m_dof is null";
			return false;
		}
		if (!depthOfFieldReflectionReady)
		{
			Type type = dof.GetType();
			dofFocusDistanceMember = FindNumericMember(type, new string[3] { "focusDistance", "focalDistance", "objectFocus" });
			dofFocalSizeMember = FindNumericMember(type, new string[2] { "focalSize", "focusRange" });
			dofMaxBlurSizeMember = FindNumericMember(type, new string[2] { "maxBlurSize", "blurSize" });
			dofApertureMember = FindNumericMember(type, new string[1] { "aperture" });
			depthOfFieldReflectionReady = true;
			depthOfFieldAvailable = dofFocusDistanceMember != null || dofFocalSizeMember != null || dofMaxBlurSizeMember != null;
			depthOfFieldStatus = (depthOfFieldAvailable ? ("native DOF members resolved on " + type.FullName) : "native DOF component found but no supported members resolved");
		}
		return depthOfFieldAvailable;
	}

	private static MemberInfo FindNumericMember(Type type, string[] candidateNames)
	{
		for (int i = 0; i < candidateNames.Length; i++)
		{
			FieldInfo field = type.GetField(candidateNames[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null && field.FieldType == typeof(float))
			{
				return field;
			}
			PropertyInfo property = type.GetProperty(candidateNames[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null && property.CanWrite && property.PropertyType == typeof(float))
			{
				return property;
			}
		}
		return null;
	}

	private static bool TrySetNumericMember(object target, MemberInfo member, float value)
	{
		if (target == null || member == null)
		{
			return false;
		}
		try
		{
			FieldInfo fieldInfo = member as FieldInfo;
			if (fieldInfo != null)
			{
				fieldInfo.SetValue(target, value);
				return true;
			}
			PropertyInfo propertyInfo = member as PropertyInfo;
			if (propertyInfo != null)
			{
				propertyInfo.SetValue(target, value, null);
				return true;
			}
		}
		catch
		{
			return false;
		}
		return false;
	}

	private float GetDepthOfFieldFocusDistance(Camera viewCamera, CameraEffects cameraEffects)
	{
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		float num = Mathf.Max(1f, depthOfFieldMaximumFocusDistance.Value);
		float result = Mathf.Clamp(depthOfFieldFallbackFocusDistance.Value, 1f, num);
		int num2 = -1;
		if (cameraEffectsDofRayMaskField != null)
		{
			try
			{
				object value = cameraEffectsDofRayMaskField.GetValue(cameraEffects);
				if (value is LayerMask val)
				{
					num2 = ((LayerMask)(ref val)).value;
				}
				else if (value != null)
				{
					num2 = Convert.ToInt32(value);
				}
			}
			catch
			{
				num2 = -1;
			}
		}
		RaycastHit val2 = default(RaycastHit);
		if (Physics.Raycast(((Component)viewCamera).transform.position, ((Component)viewCamera).transform.forward, ref val2, num, num2))
		{
			return Mathf.Clamp(((RaycastHit)(ref val2)).distance, 1f, num);
		}
		return result;
	}

	private void DestroyTunnelTextures()
	{
		if (tunnelTextures == null)
		{
			return;
		}
		for (int i = 0; i < tunnelTextures.Length; i++)
		{
			if ((Object)(object)tunnelTextures[i] != (Object)null)
			{
				Object.Destroy((Object)(object)tunnelTextures[i]);
			}
		}
		tunnelTextures = null;
	}

	private void DestroyPeripheralBlurTextures()
	{
		if (peripheralBlurTextures == null)
		{
			return;
		}
		for (int i = 0; i < peripheralBlurTextures.Length; i++)
		{
			if ((Object)(object)peripheralBlurTextures[i] != (Object)null)
			{
				Object.Destroy((Object)(object)peripheralBlurTextures[i]);
			}
		}
		peripheralBlurTextures = null;
	}

	private void DrawDiagnosticHud(Player player)
	{
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Expected O, but got Unknown
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		if (showDiagnosticHud.Value)
		{
			if (diagnosticStyle == null)
			{
				diagnosticStyle = new GUIStyle(GUI.skin.label);
				diagnosticStyle.fontSize = 15;
				diagnosticStyle.normal.textColor = Color.white;
			}
			GUI.Label(new Rect(12f, 12f, 840f, 44f), "EXERTION " + exertion.ToString("0") + "%  |  Sprint build " + sprintBuild.ToString("0.00") + "  |  Fatigue " + fatigueRecoveryActive + "  |  Slope " + cachedSlopeAngle.ToString("0") + "°  |  Wet " + cachedWet + " Cold " + cachedCold + " Freezing " + cachedFreezing + "  |  Run drain x" + lastRunDrainMultiplier.ToString("0.00"), diagnosticStyle);
		}
	}

	private void WriteDiagnostic()
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Realistic Running: no local player is available yet.");
			return;
		}
		Vector3 val = ((Character)localPlayer).GetVelocity();
		float magnitude = ((Vector3)(ref val)).magnitude;
		float directionalSpeedMultiplier = GetDirectionalSpeedMultiplier(localPlayer);
		float worldMovementMultiplier = GetWorldMovementMultiplier(localPlayer);
		float jogSpeedMultiplier = GetJogSpeedMultiplier(localPlayer);
		float runSpeedMultiplier = GetRunSpeedMultiplier(localPlayer);
		float visualIntensity = GetVisualIntensity(localPlayer);
		float highExertionFraction = GetHighExertionFraction();
		ManualLogSource logger = ((BaseUnityPlugin)this).Logger;
		string[] array = new string[103];
		array[0] = "Realistic Running diagnostic: enabled=";
		array[1] = modEnabled.Value.ToString();
		array[2] = ", running=";
		array[3] = ((Character)localPlayer).IsRunning().ToString();
		array[4] = ", moving=";
		val = ((Character)localPlayer).GetMoveDir();
		array[5] = (((Vector3)(ref val)).sqrMagnitude > 1.0000001E-06f).ToString();
		array[6] = ", stamina=";
		array[7] = ((Character)localPlayer).GetStaminaPercentage().ToString("0.000");
		array[8] = ", exertion=";
		array[9] = exertion.ToString("0.0");
		array[10] = ", visualIntensity=";
		array[11] = GetVisualIntensity(localPlayer).ToString("0.00");
		array[12] = ", sprintBuild=";
		array[13] = sprintBuild.ToString("0.00");
		array[14] = ", exhaustedJogRemaining=";
		array[15] = exhaustedJogRemaining.ToString("0.00");
		array[16] = ", fatigueRecovery=";
		array[17] = fatigueRecoveryActive.ToString();
		array[18] = ", runDrainMultiplier=";
		array[19] = lastRunDrainMultiplier.ToString("0.000");
		array[20] = ", actualVelocity=";
		array[21] = magnitude.ToString("0.00");
		array[22] = ", multipliers=[direction=";
		array[23] = directionalSpeedMultiplier.ToString("0.000");
		array[24] = ", world=";
		array[25] = worldMovementMultiplier.ToString("0.000");
		array[26] = ", jog=";
		array[27] = jogSpeedMultiplier.ToString("0.000");
		array[28] = ", run=";
		array[29] = runSpeedMultiplier.ToString("0.000");
		array[30] = "], visual=[intensity=";
		array[31] = visualIntensity.ToString("0.000");
		array[32] = ", highExertion=";
		array[33] = highExertionFraction.ToString("0.000");
		array[34] = ", swayVertical=";
		array[35] = smoothedCameraSwayVertical.ToString("0.0000");
		array[36] = ", swaySide=";
		array[37] = smoothedCameraSwaySide.ToString("0.0000");
		array[38] = ", fovBoost=";
		array[39] = smoothedSprintFovBoost.ToString("0.00");
		array[40] = "], nativeDof=[available=";
		array[41] = depthOfFieldAvailable.ToString();
		array[42] = ", status=";
		array[43] = depthOfFieldStatus;
		array[44] = "], heartbeat=[status=";
		array[45] = heartbeatStatus;
		array[46] = ", pressure=";
		array[47] = heartbeatCurrentPressure.ToString("0.00");
		array[48] = ", bpm=";
		array[49] = heartbeatCurrentBpm.ToString("0");
		array[50] = ", asset=";
		array[51] = heartbeatAssetPath;
		array[52] = "], slopeAngle=";
		array[53] = cachedSlopeAngle.ToString("0.0");
		array[54] = ", terrain=[speed=";
		array[55] = terrainSpeedMultiplier.ToString("0.00");
		array[56] = ", drain=";
		array[57] = terrainDrainMultiplier.ToString("0.00");
		array[58] = ", exertion=";
		array[59] = terrainExertionMultiplier.ToString("0.00");
		array[60] = "], weather=[wet=";
		array[61] = cachedWet.ToString();
		array[62] = ", cold=";
		array[63] = cachedCold.ToString();
		array[64] = ", freezing=";
		array[65] = cachedFreezing.ToString();
		array[66] = ", speed=";
		array[67] = weatherSpeedMultiplier.ToString("0.00");
		array[68] = ", drain=";
		array[69] = weatherDrainMultiplier.ToString("0.00");
		array[70] = ", exertion=";
		array[71] = weatherExertionMultiplier.ToString("0.00");
		array[72] = "], injury=[available=";
		array[73] = injuryReflectionUsable.ToString();
		array[74] = ", speed=";
		array[75] = injurySpeedMultiplier.ToString("0.00");
		array[76] = ", exertion=";
		array[77] = injuryExertionMultiplier.ToString("0.00");
		array[78] = "], hookCalls=[controls=";
		array[79] = setControlsHookCalls.ToString();
		array[80] = ", jog=";
		array[81] = jogSpeedHookCalls.ToString();
		array[82] = ", run=";
		array[83] = runSpeedHookCalls.ToString();
		array[84] = ", checkRun=";
		array[85] = checkRunHookCalls.ToString();
		array[86] = ", camera=";
		array[87] = cameraHookCalls.ToString();
		array[88] = ", dof=";
		array[89] = depthOfFieldHookCalls.ToString();
		array[90] = "], patches=[controls=";
		array[91] = setControlsPatchInstalled.ToString();
		array[92] = ", jog=";
		array[93] = jogSpeedPatchInstalled.ToString();
		array[94] = ", run=";
		array[95] = runSpeedPatchInstalled.ToString();
		array[96] = ", checkRun=";
		array[97] = checkRunPatchInstalled.ToString();
		array[98] = ", camera=";
		array[99] = cameraPositionPatchInstalled.ToString();
		array[100] = ", dof=";
		array[101] = depthOfFieldPatchInstalled.ToString();
		array[102] = "].";
		logger.LogInfo((object)string.Concat(array));
	}
}
public static class SurvivalMovementExertionBridge
{
	public static Func<Player, float> ExternalMovementMultiplier;

	public static Func<Player, float> ExternalRunDrainMultiplier;

	public static Func<Player, float> ExternalExertionGainMultiplier;

	public static Func<Player, float> ExternalRecoveryMultiplier;

	public static float GetMovementMultiplier(Player player)
	{
		return GetSafeMultiplier(ExternalMovementMultiplier, player, 0.2f, 1.35f);
	}

	public static float GetRunDrainMultiplier(Player player)
	{
		return GetSafeMultiplier(ExternalRunDrainMultiplier, player, 0.25f, 4f);
	}

	public static float GetExertionGainMultiplier(Player player)
	{
		return GetSafeMultiplier(ExternalExertionGainMultiplier, player, 0.25f, 4f);
	}

	public static float GetRecoveryMultiplier(Player player)
	{
		return GetSafeMultiplier(ExternalRecoveryMultiplier, player, 0.1f, 2f);
	}

	private static float GetSafeMultiplier(Func<Player, float> provider, Player player, float minimum, float maximum)
	{
		if (provider == null)
		{
			return 1f;
		}
		try
		{
			return Mathf.Clamp(provider(player), minimum, maximum);
		}
		catch
		{
			return 1f;
		}
	}
}
internal struct WindStreak
{
	public readonly float AngleRadians;

	public readonly float InnerRadius;

	public readonly float Phase;

	public readonly float Speed;

	public readonly float Length;

	public readonly float Alpha;

	public WindStreak(float angleRadians, float innerRadius, float phase, float speed, float length, float alpha)
	{
		AngleRadians = angleRadians;
		InnerRadius = innerRadius;
		Phase = phase;
		S