Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of RealisticRunning v1.6.11
RealisticRunning.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("SurvivalMovementExertion")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("SurvivalMovementExertion")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("21978fe2-ee63-49ee-aad5-3609c97f40b0")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace SurvivalMovementExertion; internal sealed class AudioFadeEnvelope { private float start; private float target; private float elapsed; public float Value { get; private set; } public float Step(float requestedTarget, float dt, float duration) { requestedTarget = Math.Max(0f, Math.Min(1f, requestedTarget)); if (requestedTarget != target) { start = Value; target = requestedTarget; elapsed = 0f; } elapsed += Math.Max(0f, dt); float num = ((duration <= 0f) ? 1f : Math.Min(1f, elapsed / duration)); float num2 = num * num * (3f - 2f * num); Value = start + (target - start) * num2; if (num >= 1f) { Value = target; } return Value; } public void Reset() { float num = (Value = 0f); start = (target = (elapsed = num)); } } internal static class ExertionVisualDriver { internal static float MapExertion(float percentage) { percentage = Math.Max(0f, Math.Min(100f, percentage)); if (percentage <= 20f) { return percentage * 0.0165f; } if (percentage <= 40f) { return 0.33f + (percentage - 20f) * 0.0165f; } return 0.66f + (percentage - 40f) * 0.0056666667f; } internal static float Step(float current, float target, float deltaTime, float timeConstant) { float num = (float)(1.0 - Math.Exp((0f - Math.Max(0f, deltaTime)) / Math.Max(0.1f, timeConstant))); return current + (target - current) * num; } } [RequireComponent(typeof(Camera))] public sealed class ExertionVisualRenderer : MonoBehaviour { private static Shader peripheralShader; private Material material; private bool initializationAttempted; private float intensity; private readonly PeripheralMotionAwareness motionAwareness = new PeripheralMotionAwareness(); private bool enableMotionAwareness; private float motionAwarenessStrength; private float motionClearRadius; public string MotionAwarenessStatus => motionAwareness.Status; public string Status { get; private set; } = "not initialized"; public float SaturationMultiplier { get; private set; } = 1f; public int RenderedFrames { get; private set; } public void Configure(float sharedIntensity, float blurStrength, float clarityStrength, float clearRadius, float visualSaturation, bool enablePeripheralMotionAwareness = false, float peripheralMotionAwarenessStrength = 0.65f) { //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Expected O, but got Unknown intensity = sharedIntensity; enableMotionAwareness = enablePeripheralMotionAwareness; motionAwarenessStrength = peripheralMotionAwarenessStrength; motionClearRadius = clearRadius; if (!enableMotionAwareness) { motionAwareness.Reset(); } SaturationMultiplier = visualSaturation; if (!initializationAttempted) { initializationAttempted = true; try { if ((Object)(object)peripheralShader == (Object)null) { using Stream stream = typeof(ExertionVisualRenderer).Assembly.GetManifestResourceStream("RealisticRunning.exertionvisuals"); if (stream == null) { throw new InvalidOperationException("Embedded visual shader bundle is missing."); } using BinaryReader binaryReader = new BinaryReader(stream); AssetBundle val = AssetBundle.LoadFromMemory(binaryReader.ReadBytes((int)stream.Length)); if ((Object)(object)val == (Object)null) { throw new InvalidOperationException("Could not load visual shader bundle."); } try { peripheralShader = val.LoadAsset<Shader>("Assets/ExertionPeripheral.shader"); } finally { val.Unload(false); } } if ((Object)(object)peripheralShader == (Object)null || !peripheralShader.isSupported) { throw new InvalidOperationException("Peripheral visual shader is unavailable or unsupported."); } material = new Material(peripheralShader) { hideFlags = (HideFlags)61 }; Status = "ready: masked radial blur + clarity"; } catch (Exception ex) { Status = "FAILED: " + ex.Message; Debug.LogError((object)("Realistic Running visuals: " + Status)); } } if (!((Object)(object)material == (Object)null)) { material.SetFloat("_Intensity", sharedIntensity); material.SetFloat("_BlurStrength", blurStrength); material.SetFloat("_SharpenStrength", clarityStrength); material.SetFloat("_ClearRadius", clearRadius); material.SetFloat("_SaturationMultiplier", SaturationMultiplier); } } private void OnPreCull() { if (enableMotionAwareness) { motionAwareness.Prepare(((Component)this).GetComponent<Camera>()); } } private void OnRenderImage(RenderTexture source, RenderTexture destination) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)material == (Object)null || intensity <= 1E-05f) { Graphics.Blit((Texture)(object)source, destination); return; } if (!enableMotionAwareness) { Graphics.Blit((Texture)(object)source, destination, material); } else { RenderTexture temporary = RenderTexture.GetTemporary(source.descriptor); try { Graphics.Blit((Texture)(object)source, temporary, material); if (!motionAwareness.Apply(((Component)this).GetComponent<Camera>(), source, temporary, destination, motionAwarenessStrength, motionClearRadius)) { Graphics.Blit((Texture)(object)temporary, destination); } } finally { RenderTexture.ReleaseTemporary(temporary); } } RenderedFrames++; } private void OnDestroy() { motionAwareness.Dispose(); if ((Object)(object)material != (Object)null) { Object.Destroy((Object)(object)material); } } private void OnDisable() { motionAwareness.Reset(); } } internal enum MovementAudioPhase { Silent, Start, Flow, Hill, Push, Adrenaline } internal sealed class MovementAudioSequencer { private float stoppedSeconds; private float climbingSeconds; private float hillReleaseSeconds; private bool hillActive; public float RunSeconds { get; private set; } public MovementAudioPhase Phase { get; private set; } public void Reset() { float num = (RunSeconds = 0f); stoppedSeconds = (climbingSeconds = (hillReleaseSeconds = num)); hillActive = false; Phase = MovementAudioPhase.Silent; } public MovementAudioPhase Step(bool running, bool climbing, MovementAudioPhase burst, float deltaSeconds, float startSeconds) { float num = Math.Max(0f, deltaSeconds); if (!running) { stoppedSeconds += num; if (stoppedSeconds >= 0.25f) { Reset(); } return MovementAudioPhase.Silent; } stoppedSeconds = 0f; RunSeconds += num; bool flag = RunSeconds >= Math.Max(0.1f, startSeconds); if (!flag) { climbingSeconds = (hillReleaseSeconds = 0f); hillActive = false; } else if (climbing) { climbingSeconds += num; hillReleaseSeconds = 0f; if (climbingSeconds >= 0.75f) { hillActive = true; } } else { climbingSeconds = 0f; hillReleaseSeconds += num; if (hillReleaseSeconds >= 1.5f) { hillActive = false; } } if (burst == MovementAudioPhase.Push || burst == MovementAudioPhase.Adrenaline) { Phase = burst; } else { Phase = ((!flag) ? MovementAudioPhase.Start : (hillActive ? MovementAudioPhase.Hill : MovementAudioPhase.Flow)); } return Phase; } } internal sealed class PeripheralMotionAwareness : IDisposable { private Material material; private RenderTexture previousScene; private RenderTexture previousDepth; private Matrix4x4 previousViewProjection; private Vector3 previousPosition; private Quaternion previousRotation; private float previousFar; private float previousFov; private float previousTime; private bool historyValid; private bool failed; public string Status { get; private set; } = "disabled"; public void Reset() { historyValid = false; Release(ref previousScene); Release(ref previousDepth); Status = (failed ? "unavailable; original rendering retained" : "disabled"); } public void Prepare(Camera camera) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)camera != (Object)null && !failed) { camera.depthTextureMode = (DepthTextureMode)(camera.depthTextureMode | 1); } } public bool Apply(Camera camera, RenderTexture source, RenderTexture processed, RenderTexture destination, float strength, float clearRadius) { //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_0391: Unknown result type (might be due to invalid IL or missing references) //IL_0393: Unknown result type (might be due to invalid IL or missing references) //IL_03ab: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_03bc: Unknown result type (might be due to invalid IL or missing references) //IL_03c1: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown if (failed || (Object)(object)camera == (Object)null || camera.orthographic) { return false; } try { if ((Object)(object)material == (Object)null) { using Stream stream = typeof(PeripheralMotionAwareness).Assembly.GetManifestResourceStream("RealisticRunning.exertionvisuals"); using BinaryReader binaryReader = new BinaryReader(stream); AssetBundle val = AssetBundle.LoadFromMemory(binaryReader.ReadBytes((int)stream.Length)); if ((Object)(object)val == (Object)null) { throw new InvalidOperationException("Motion-awareness bundle unavailable."); } Shader val2; try { val2 = val.LoadAsset<Shader>("Assets/PeripheralMotionAwareness.shader"); } finally { val.Unload(false); } if ((Object)(object)val2 == (Object)null || !val2.isSupported) { throw new InvalidOperationException("Motion-awareness shader unsupported."); } material = new Material(val2) { hideFlags = (HideFlags)61 }; } if ((Object)(object)previousScene == (Object)null || ((Texture)previousScene).width != ((Texture)source).width || ((Texture)previousScene).height != ((Texture)source).height || previousScene.format != source.format) { Reset(); previousScene = Create(((Texture)source).width, ((Texture)source).height, source.format); RenderTextureFormat format = (RenderTextureFormat)(SystemInfo.SupportsRenderTextureFormat((RenderTextureFormat)14) ? 14 : 2); previousDepth = Create(((Texture)source).width, ((Texture)source).height, format); } float unscaledTime = Time.unscaledTime; float num = unscaledTime - previousTime; bool flag = historyValid && num > 0f && num < 0.2f && Vector3.Distance(((Component)camera).transform.position, previousPosition) < 2f && Quaternion.Angle(((Component)camera).transform.rotation, previousRotation) < 20f && Mathf.Abs(camera.fieldOfView - previousFov) < 2f; Matrix4x4 val3 = GL.GetGPUProjectionMatrix(camera.projectionMatrix, false) * camera.worldToCameraMatrix; material.SetTexture("_SceneTex", (Texture)(object)source); material.SetVector("_SceneTex_TexelSize", new Vector4(1f / (float)((Texture)source).width, 1f / (float)((Texture)source).height, (float)((Texture)source).width, (float)((Texture)source).height)); material.SetTexture("_PreviousScene", (Texture)(object)previousScene); material.SetTexture("_PreviousDepth", (Texture)(object)previousDepth); material.SetMatrix("_InverseViewProjection", ((Matrix4x4)(ref val3)).inverse); material.SetMatrix("_PreviousViewProjection", previousViewProjection); material.SetFloat("_PreviousFar", Mathf.Max(1f, previousFar)); material.SetFloat("_FrameSeconds", num); material.SetFloat("_ClearRadius", clearRadius); material.SetFloat("_Strength", flag ? Mathf.Clamp01(strength) : 0f); Graphics.Blit((Texture)(object)processed, destination, material, 0); Graphics.Blit((Texture)(object)source, previousScene); Graphics.Blit((Texture)(object)source, previousDepth, material, 1); previousViewProjection = val3; previousFar = camera.farClipPlane; previousPosition = ((Component)camera).transform.position; previousRotation = ((Component)camera).transform.rotation; previousFov = camera.fieldOfView; previousTime = unscaledTime; historyValid = true; Status = (flag ? "camera-compensated motion contrast active" : "history reset (no enhancement)"); return true; } catch (Exception) { failed = true; Dispose(); Status = "unavailable; original rendering retained"; return false; } } private static RenderTexture Create(int width, int height, RenderTextureFormat format) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown RenderTexture val = new RenderTexture(width, height, 0, format, (RenderTextureReadWrite)1) { hideFlags = (HideFlags)61, filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; if (!val.Create()) { Object.Destroy((Object)(object)val); throw new InvalidOperationException("Motion history allocation failed."); } return val; } private static void Release(ref RenderTexture texture) { if ((Object)(object)texture != (Object)null) { texture.Release(); Object.Destroy((Object)(object)texture); } texture = null; } public void Dispose() { Reset(); if ((Object)(object)material != (Object)null) { Object.Destroy((Object)(object)material); } material = null; } } [BepInPlugin("com.marccunningham.survivalmovementexertion", "Realistic Running", "1.6.11")] [BepInProcess("valheim.exe")] public sealed class SurvivalMovementExertionPlugin : BaseUnityPlugin { private enum PushState { Normal, Pushing, Adrenaline, RecoveryOne, RecoveryTwo } private sealed class LoopingAudioLayer { public AudioSource Source; public AudioClip Clip; public readonly AudioFadeEnvelope Fade = new AudioFadeEnvelope(); public string Status = "not loaded"; public string AssetPath = string.Empty; public float CurrentVolume => Fade.Value; } public const string PluginGuid = "com.marccunningham.survivalmovementexertion"; public const string PluginName = "Realistic Running"; public const string PluginVersion = "1.6.11"; private const float MinimumInputMagnitude = 0.001f; private const float MinimumDuration = 0.01f; private const int TunnelTextureCount = 18; private const int TunnelTextureSize = 160; private const int DefaultWindStreakCount = 28; private const string ZdoPushState = "RealisticRunning_PushState"; private const string ZdoPushStateRemaining = "RealisticRunning_PushStateRemaining"; private const string ZdoPushMovementRecovery = "RealisticRunning_PushMovementRecovery"; private const string ZdoPushMinimumRecoveryRemaining = "RealisticRunning_PushMinimumRecoveryRemaining"; private const float ZdoMissingPushState = -1f; internal static SurvivalMovementExertionPlugin Instance; private ConfigEntry<bool> modEnabled; private ConfigEntry<KeyCode> diagnosticKey; private ConfigEntry<bool> showDiagnosticHud; private ConfigEntry<bool> enableDebugControls; private ConfigEntry<bool> enableVerboseLogging; private ConfigEntry<bool> enableInputSmoothing; private ConfigEntry<float> accelerationSeconds; private ConfigEntry<float> decelerationSeconds; private ConfigEntry<float> backwardSpeedMultiplier; private ConfigEntry<float> sidewaysSpeedMultiplier; private ConfigEntry<float> sprintBuildUpSeconds; private ConfigEntry<float> sprintStartSpeedFraction; private ConfigEntry<float> topSprintSpeedMultiplier; private ConfigEntry<float> sprintBuildRecoverySeconds; private ConfigEntry<float> baseRunStaminaDrainMultiplier; private ConfigEntry<float> maximumCombinedRunDrainMultiplier; private ConfigEntry<float> emergencySprintReleaseStaminaPercentage; private ConfigEntry<bool> enablePushStateMachine; private ConfigEntry<float> pushTapRatePerSecond; private ConfigEntry<float> pushTapSustainSeconds; private ConfigEntry<float> pushTapGraceSeconds; private ConfigEntry<float> adrenalineContinuousTapSeconds; private ConfigEntry<float> pushSpeedMultiplier; private ConfigEntry<float> adrenalineSpeedMultiplier; private ConfigEntry<float> adrenalineStaminaDrainMultiplier; private ConfigEntry<float> adrenalineOnsetSeconds; private ConfigEntry<float> adrenalineOnsetFov; private ConfigEntry<float> adrenalineCombatRange; private ConfigEntry<float> adrenalineFacingDotThreshold; private ConfigEntry<float> adrenalineHeartbeatBaselineBpm; private ConfigEntry<float> adrenalineCombatHeartbeatMultiplier; private ConfigEntry<float> adrenalineCombatDecayNearSeconds; private ConfigEntry<float> adrenalineCombatDecayFarSeconds; private ConfigEntry<float> pushStaminaDrainMultiplier; private ConfigEntry<float> eTapNativeStaminaCost; private ConfigEntry<float> recoveryOneJogCapSeconds; private ConfigEntry<float> recoveryOneBreathingTaperSeconds; private ConfigEntry<float> recoveryTwoWalkOnlySeconds; private ConfigEntry<float> flatSlopeDrainBonus; private ConfigEntry<float> exertionGainPerSecond; private ConfigEntry<float> exertionRecoveryPerSecond; private ConfigEntry<float> stationaryRecoveryMultiplier; private ConfigEntry<float> highExertionStart; private ConfigEntry<float> highExertionRunSpeedMultiplier; private ConfigEntry<float> highExertionDrainMultiplier; private ConfigEntry<float> exhaustionTriggerStaminaPercentage; private ConfigEntry<float> exhaustedJogSeconds; private ConfigEntry<float> exhaustedJogSpeedMultiplier; private ConfigEntry<float> recoveryStaminaPercentage; private ConfigEntry<float> recoveryExertionPercentage; private ConfigEntry<bool> enableHillEffects; private ConfigEntry<float> hillGraceAngle; private ConfigEntry<float> hillFullPenaltyAngle; private ConfigEntry<float> uphillSpeedPenalty; private ConfigEntry<float> uphillDrainMultiplier; private ConfigEntry<float> uphillExertionMultiplier; private ConfigEntry<float> downhillSpeedBonus; private ConfigEntry<float> downhillDrainReduction; private ConfigEntry<bool> enableWeatherEffects; private ConfigEntry<float> wetSpeedMultiplier; private ConfigEntry<float> wetDrainMultiplier; private ConfigEntry<float> wetExertionMultiplier; private ConfigEntry<float> coldDrainMultiplier; private ConfigEntry<float> coldExertionMultiplier; private ConfigEntry<float> freezingSpeedMultiplier; private ConfigEntry<float> freezingDrainMultiplier; private ConfigEntry<float> freezingExertionMultiplier; private ConfigEntry<bool> enableInjuryCompatibility; private ConfigEntry<float> injuryExertionPenaltyStrength; private ConfigEntry<bool> applyInjurySpeedCompatibilityPenalty; private ConfigEntry<float> factorRefreshSeconds; private ConfigEntry<bool> enableTunnelVision; private ConfigEntry<float> tunnelVisionStartExertion; private ConfigEntry<float> tunnelVisionFullExertion; private ConfigEntry<float> maximumTunnelVisionAlpha; private ConfigEntry<float> tunnelVisionPulseStrength; private ConfigEntry<float> tunnelVisionClearRadiusAtExhaustion; private ConfigEntry<bool> enableWindRushStreaks; private ConfigEntry<int> windRushStreakCount; private ConfigEntry<float> windRushStartSprintBuild; private ConfigEntry<float> windRushMaximumAlpha; private ConfigEntry<float> windRushTravelSpeed; private ConfigEntry<bool> enableCameraSway; private ConfigEntry<bool> cameraSwayClosestZoomOnly; private ConfigEntry<float> closestZoomTolerance; private ConfigEntry<float> sprintBobVerticalMeters; private ConfigEntry<float> sprintBobSideMeters; private ConfigEntry<float> fatigueBreathSwayMeters; private ConfigEntry<float> sprintSwayFrequencyLow; private ConfigEntry<float> sprintSwayFrequencyHigh; private ConfigEntry<float> breathSwayFrequencyLow; private ConfigEntry<float> breathSwayFrequencyHigh; private ConfigEntry<float> cameraSwaySmoothingSeconds; private ConfigEntry<float> coolEdgeTintStrength; private ConfigEntry<bool> enableNativeDepthOfField; private ConfigEntry<bool> depthOfFieldClosestZoomOnly; private ConfigEntry<float> depthOfFieldStartVisualIntensity; private ConfigEntry<float> depthOfFieldMaximumBlurSize; private ConfigEntry<float> depthOfFieldFocalSizeAtExhaustion; private ConfigEntry<float> depthOfFieldFallbackFocusDistance; private ConfigEntry<float> depthOfFieldMaximumFocusDistance; private ConfigEntry<float> flowStateBaseFov; private ConfigEntry<float> flowStateMaximumFov; private ConfigEntry<float> pushStateFov; private ConfigEntry<float> adrenalineStateFov; private ConfigEntry<float> visualTierTransitionSeconds; private ConfigEntry<float> adrenalineAudioFadeSeconds; private ConfigEntry<float> exertionVisualTimeConstantSeconds; private ConfigEntry<bool> enableControlledMotionBlur; private ConfigEntry<bool> enableFlowColorSaturation; private ConfigEntry<float> flowSaturationMultiplier; private ConfigEntry<bool> enableFlowClarity; private ConfigEntry<float> flowClarityStrength; private ConfigEntry<float> peripheralMotionBlurStrength; private ConfigEntry<bool> enablePeripheralMotionAwareness; private ConfigEntry<float> peripheralMotionAwarenessStrength; private ConfigEntry<bool> enablePeripheralBlurOverlay; private ConfigEntry<float> peripheralBlurStartIntensity; private ConfigEntry<float> peripheralBlurMaximumAlpha; private ConfigEntry<float> peripheralBlurClearRadiusAtExhaustion; private ConfigEntry<bool> enableExhaustionHeartbeat; private ConfigEntry<float> heartbeatStartPressure; private ConfigEntry<float> heartbeatRecoveryBpm; private ConfigEntry<float> heartbeatMaximumBpm; private ConfigEntry<float> heartbeatMaximumVolume; private ConfigEntry<float> heartbeatIntensitySmoothingSeconds; private ConfigEntry<bool> enableMovementAudio; private ConfigEntry<float> shallowBreathVolume; private ConfigEntry<float> flowBreathVolume; private ConfigEntry<float> heavyBreathVolume; private ConfigEntry<float> stompFootstepVolume; private ConfigEntry<float> runStartAudioSeconds; private ConfigEntry<float> movementAudioCrossfadeSeconds; private ConfigEntry<bool> enableBaselineExhaustionBreathing; private ConfigEntry<float> exhaustionBreathRestRecoverySeconds; private ConfigEntry<float> exhaustionBreathJogRecoverySeconds; private ConfigEntry<float> exhaustionBreathInitialVolume; private ConfigEntry<float> exhaustionBreathInitialPitch; private ConfigEntry<bool> showRecoverySeconds; private Harmony harmony; private bool setControlsPatchInstalled; private bool jogSpeedPatchInstalled; private bool runSpeedPatchInstalled; private bool checkRunPatchInstalled; private bool recoveryWalkingPatchInstalled; private bool lastSprintInputRequested; private Player visualInputPlayer; private bool visualRawMovementRequested; private bool visualSprintRequested; private bool cameraPositionPatchInstalled; private bool cameraFovPatchInstalled; private bool cameraFovSourcePatchInstalled; private bool cameraFovLatePatchInstalled; private GameCamera ownedFovManager; private bool nativeFovClaimed; private float nativeFovBeforeClaim; private float nativeFovTargetBeforeClaim; private Camera gameplayCamera; private int cameraFovHookCalls; private float lastAppliedFov = 60f; private bool depthOfFieldPatchInstalled; private int setControlsHookCalls; private int jogSpeedHookCalls; private int runSpeedHookCalls; private int checkRunHookCalls; private int cameraHookCalls; private int depthOfFieldHookCalls; private float smoothedInputMagnitude; private float sprintBuild; private float exertion; private float exhaustedJogRemaining; private bool fatigueRecoveryActive; private bool baselineMovementRecoveryActive; private bool wasSprinting; private bool baselineExhaustionBreathingActive; private bool baselineExhaustionBreathingCompleted; private float baselineExhaustionBreathingProgress; private bool baselineSprintAttemptWasHeld; private float baselineExhaustionNextGaspTime; private string baselineExhaustionBreathingStatus = "idle"; private float lastRunDrainMultiplier = 1f; private float factorRefreshTimer = 999f; private PushState pushState; private float pushStateRemaining; private bool pushMovementRecoveryActive; private float pushMinimumRecoveryRemaining; private float lastObservedStaminaForAdrenalineRefund = -1f; private float adrenalineRefundTotalDrop; private float adrenalineRefundTotalRefunded; private float adrenalineRefundNextLogTime; private readonly Queue<float> tapTimes = new Queue<float>(); private float fastTapStartedAt = -1f; private float lastFastTapSatisfiedTime = -1f; private bool cachedClimbingSlope; private bool pushStateLoaded; private float pushStateSaveTimer; private float adrenalineFovOverride = -1f; private float adrenalineCombatSpike; private float adrenalineCombatLostAt = -1f; private float adrenalineLastEnemyDistance = float.MaxValue; private bool adrenalineOnsetAudioMuted; private float audioListenerVolumeBeforeAdrenalineMute = 1f; private float adrenalineAudioDuckBlend; private MethodInfo getAllCharactersMethod; private MethodInfo isMonsterFactionMethod; private float terrainSpeedMultiplier = 1f; private float terrainDrainMultiplier = 1f; private float terrainExertionMultiplier = 1f; private float weatherSpeedMultiplier = 1f; private float weatherDrainMultiplier = 1f; private float weatherExertionMultiplier = 1f; private float weatherRecoveryMultiplier = 1f; private float injurySpeedMultiplier = 1f; private float injuryExertionMultiplier = 1f; private float cachedSlopeAngle; private bool cachedWet; private bool cachedCold; private bool cachedFreezing; private float smoothedCameraSwayVertical; private float smoothedCameraSwaySide; private float cameraSwayVerticalVelocity; private float cameraSwaySideVelocity; private float latestCameraDistance = float.MaxValue; private float latestCameraMinimumDistance = float.MaxValue; private float smoothedExertionVisual; private float targetExertionVisual; private float visualTransitionFromTier; private float visualTransitionToTier = -1f; private float visualTransitionElapsed; private ExertionVisualRenderer exertionVisualRenderer; private const float WindRushClearRadius = 0.42f; private Component heartbeatAudioSource; private Object heartbeatClip; private MethodInfo heartbeatPlayOneShotMethod; private MethodInfo heartbeatStopMethod; private bool audioPausedByMenu; private float heartbeatNextBeatTime; private float heartbeatCurrentPressure; private float heartbeatPressureVelocity; private float heartbeatCurrentBpm; private string heartbeatStatus = "not loaded"; private string heartbeatAssetPath = string.Empty; private LoopingAudioLayer shallowBreathLayer; private LoopingAudioLayer flowBreathLayer; private LoopingAudioLayer heavyBreathLayer; private LoopingAudioLayer stompFootstepLayer; private readonly MovementAudioSequencer movementAudioSequence = new MovementAudioSequencer(); private string lastMovementAudioSelection = string.Empty; private bool audioDebugMuted; private int audioSoloPreview; private FieldInfo cameraEffectsDofField; private FieldInfo cameraEffectsDofRayMaskField; private FieldInfo cameraEffectsMotionBlurField; private MemberInfo postProcessingProfileMember; private MemberInfo postProcessingMotionBlurMember; private MemberInfo dofFocusDistanceMember; private MemberInfo dofFocalSizeMember; private MemberInfo dofMaxBlurSizeMember; private MemberInfo dofApertureMember; private bool depthOfFieldReflectionReady; private bool depthOfFieldAvailable; private string depthOfFieldStatus = "not resolved"; private MemberInfo motionBlurEnabledMember; private bool motionBlurReflectionReady; private bool motionBlurAvailable; private string motionBlurStatus = "not resolved"; private string flowColorStatus = "not resolved"; private Type injuryPluginType; private FieldInfo injuryInstanceField; private MethodInfo injuryIsActiveForMethod; private MethodInfo injuryRunSpeedMultiplierMethod; private bool injuryReflectionUsable; private FieldInfo survivalViewExternalFovAuthorityField; private FieldInfo survivalViewExternalMovementAuthorityField; private Delegate survivalViewAuthorityDelegate; private bool survivalViewAuthorityClaimed; private Texture2D[] tunnelTextures; private Texture2D[] peripheralBlurTextures; private WindStreak[] windStreaks; private GUIStyle diagnosticStyle; private FieldInfo hudInstanceField; private FieldInfo hudStaminaBarRootField; private MethodInfo hudIsVisibleMethod; private bool nativeStaminaBarHiddenByUs; private ConfigEntry<bool> enableBloodPulse; private ConfigEntry<float> bloodPulseMinVolume; private ConfigEntry<float> bloodPulseMaxVolume; private ConfigEntry<float> bloodPulseVignetteMaxAlpha; private Component bloodPulseAudioSource; private Object bloodPulseClip; private string bloodPulseStatus = "not loaded"; private string bloodPulseAssetPath = string.Empty; private float bloodPulseVignetteAlpha; private float lastHeartbeatBeatTime = -999f; private float lastHeartbeatBeatVolume = 1f; private Texture2D bloodPulseVignetteTexture; private void Awake() { Instance = this; BindConfig(); TryClaimSurvivalViewAuthority(); MigratePerceptibilityDefaults(); MigrateEscapeSafetyDefaults(); MigratePushStateDefaults(); MigrateFlowFovDefaults(); MigrateMovementAudioDefaults(); InstallPatches(); TryLoadHeartbeatAudio(); TryLoadBloodPulseAudio(); TryLoadMovementAudio(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Realistic Running 1.6.11 loaded."); } private void LogVerbose(string message) { if (enableVerboseLogging != null && enableVerboseLogging.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)message); } } private void OnDestroy() { RestoreNativeFovOwnership(); if ((Object)(object)exertionVisualRenderer != (Object)null) { Object.Destroy((Object)(object)exertionVisualRenderer); } TrySavePushState(); if (harmony != null) { harmony.UnpatchSelf(); } ReleaseSurvivalViewAuthority(); EndAdrenalineOnsetAudioMute(immediate: true); ApplyNativeStaminaBarVisibility(visible: true); StopHeartbeatAudio(); StopBloodPulseAudio(); DestroyMovementAudio(); if ((Object)(object)heartbeatAudioSource != (Object)null) { Object.Destroy((Object)(object)heartbeatAudioSource); heartbeatAudioSource = null; } if (heartbeatClip != (Object)null) { Object.Destroy(heartbeatClip); heartbeatClip = null; } if ((Object)(object)bloodPulseAudioSource != (Object)null) { Object.Destroy((Object)(object)bloodPulseAudioSource); bloodPulseAudioSource = null; } if (bloodPulseClip != (Object)null) { Object.Destroy(bloodPulseClip); bloodPulseClip = null; } if ((Object)(object)bloodPulseVignetteTexture != (Object)null) { Object.Destroy((Object)(object)bloodPulseVignetteTexture); bloodPulseVignetteTexture = null; } DestroyTunnelTextures(); DestroyPeripheralBlurTextures(); windStreaks = null; if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void Update() { //IL_0295: Unknown result type (might be due to invalid IL or missing references) if (IsGamePaused()) { StopMovementAudio(); StopHeartbeatAudio(); StopBloodPulseAudio(); StopAllRecognizedRunningAudio(); EndAdrenalineOnsetAudioMute(); bloodPulseVignetteAlpha = 0f; audioPausedByMenu = true; return; } if (audioPausedByMenu) { audioPausedByMenu = false; heartbeatNextBeatTime = Time.unscaledTime + 0.1f; baselineExhaustionNextGaspTime = Time.time; baselineSprintAttemptWasHeld = lastSprintInputRequested; } if (enableDebugControls.Value) { if (Input.GetKeyDown((KeyCode)288)) { Player localPlayer = Player.m_localPlayer; if (IsMovementEligible(localPlayer) && enablePushStateMachine.Value) { pushState = PushState.Adrenaline; pushStateRemaining = 210f; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Realistic Running: F7 debug-forced entry into Adrenaline. stamina=" + localPlayer.GetStamina().ToString("0.00") + "/" + ((Character)localPlayer).GetMaxStamina().ToString("0.00"))); } } if (Input.GetKeyDown((KeyCode)291)) { audioSoloPreview = (audioSoloPreview + 1) % 5; StopMovementAudio(); StopHeartbeatAudio(); StopBloodPulseAudio(); StopAllRecognizedRunningAudio(); movementAudioSequence.Reset(); lastMovementAudioSelection = string.Empty; audioDebugMuted = false; if ((Object)(object)heartbeatAudioSource != (Object)null) { SetNumericProperty(((object)heartbeatAudioSource).GetType(), heartbeatAudioSource, "volume", 1f); } ((BaseUnityPlugin)this).Logger.LogInfo((object)("Realistic Running: F10 solo preview=" + GetAudioSoloPreviewName() + ". Previews play without running; all other RR audio is stopped.")); } if (Input.GetKeyDown((KeyCode)290)) { audioDebugMuted = !audioDebugMuted; if (audioDebugMuted) { StopMovementAudio(); StopHeartbeatAudio(); StopBloodPulseAudio(); StopAllRecognizedRunningAudio(); } else if ((Object)(object)heartbeatAudioSource != (Object)null) { SetNumericProperty(((object)heartbeatAudioSource).GetType(), heartbeatAudioSource, "volume", 1f); } ((BaseUnityPlugin)this).Logger.LogInfo((object)("Realistic Running: F9 audio mute=" + audioDebugMuted + ". F8 prints all audible Unity sources.")); WriteLiveAudioAudit(); } if (Input.GetKeyDown(diagnosticKey.Value)) { WriteDiagnostic(); } } if (audioSoloPreview != 0) { UpdateAudioSoloPreview(); } Player localPlayer2 = Player.m_localPlayer; if (!IsMovementEligible(localPlayer2)) { lastObservedStaminaForAdrenalineRefund = -1f; EndAdrenalineOnsetAudioMute((Object)(object)localPlayer2 == (Object)null || ((Character)localPlayer2).IsDead()); ResetTransientMovementState(); UpdateExertionVisual(localPlayer2); return; } EnsurePushStateLoaded(localPlayer2); RecordTapInput(localPlayer2); ApplyPushTierStaminaRefund(localPlayer2); UpdatePushState(localPlayer2); UpdatePushMovementRecovery(localPlayer2, Time.deltaTime); SavePushStateIfDue(localPlayer2); factorRefreshTimer += Time.deltaTime; if (factorRefreshTimer >= Mathf.Max(0.05f, factorRefreshSeconds.Value)) { factorRefreshTimer = 0f; RefreshWorldFactors(localPlayer2); TryClaimSurvivalViewAuthority(); } UpdateExertion(localPlayer2); UpdateAdrenalineSensory(localPlayer2); UpdateExertionVisual(localPlayer2); UpdateVisualMotion(localPlayer2); UpdateHeartbeatAudio(localPlayer2); UpdateMovementAudio(localPlayer2); UpdateBaselineExhaustionBreathing(localPlayer2); } private void OnGUI() { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && modEnabled.Value) { DrawWindRush(localPlayer); DrawPeripheralBlur(localPlayer); DrawTunnelVision(localPlayer); DrawBloodPulseVignette(); DrawRecoveryStatus(localPlayer); DrawDiagnosticHud(localPlayer); } } private void BindConfig() { //IL_0ba1: Unknown result type (might be due to invalid IL or missing references) //IL_0bc4: Unknown result type (might be due to invalid IL or missing references) //IL_0bce: Expected O, but got Unknown //IL_0bce: Expected O, but got Unknown modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Turns Realistic Running on or off without removing the DLL."); diagnosticKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Debug", "DiagnosticKey", (KeyCode)289, "Diagnostic key used only while EnableDebugControls is true."); enableDebugControls = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableDebugControls", false, "Enables test-only F7/F8/F9/F10 controls. Leave disabled during normal play."); enableVerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableVerboseLogging", false, "Writes detailed audio transitions, state changes and stamina accounting to BepInEx/LogOutput.log. Leave disabled during normal play."); showDiagnosticHud = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "ShowDiagnosticHud", false, "Shows a small top-left exertion readout for balancing. Leave off for normal play."); enableInputSmoothing = ((BaseUnityPlugin)this).Config.Bind<bool>("Movement", "EnableInputSmoothing", true, "Smooths input magnitude while preserving immediate turning direction. This creates acceleration and deceleration without steering lag."); accelerationSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "AccelerationSeconds", 0.28f, "Seconds for a stationary player to build toward full movement input. Higher values feel heavier."); decelerationSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "DecelerationSeconds", 0.18f, "Seconds for movement input to settle after keys are released. Higher values feel less abrupt."); backwardSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "BackwardSpeedMultiplier", 0.7f, "Speed while moving directly backward. Diagonal movement blends naturally between forward, sideways and backward values."); sidewaysSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "SidewaysSpeedMultiplier", 0.86f, "Speed while moving directly sideways."); sprintBuildUpSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Sprint", "SprintBuildUpSeconds", 1.35f, "Seconds for sprinting to build from the initial run into maximum speed."); sprintStartSpeedFraction = ((BaseUnityPlugin)this).Config.Bind<float>("Sprint", "SprintStartSpeedFraction", 0.72f, "Fraction of top sprint speed available the instant sprinting begins. It rises to full TopSprintSpeedMultiplier over SprintBuildUpSeconds. V1.1.1 starts close to normal run speed, then visibly builds into a faster sprint."); topSprintSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Sprint", "TopSprintSpeedMultiplier", 1.45f, "Maximum healthy forward sprint multiplier relative to Valheim's native running speed. V1.1.4 gives a clearly faster full sprint while retaining build-up, exertion and recovery."); sprintBuildRecoverySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Sprint", "SprintBuildRecoverySeconds", 0.6f, "Seconds for sprint build-up to fade after the player stops running."); baseRunStaminaDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Sprint", "BaseRunStaminaDrainMultiplier", 0.15f, "Multiplier applied to Valheim's native run stamina drain. 0.15 aims for roughly 45-60 seconds of healthy sustained running with the same stamina pool, before terrain and exertion are considered."); maximumCombinedRunDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Safety", "MaximumCombinedRunDrainMultiplier", 2.25f, "Safety cap for all combined run-drain effects from exertion, terrain, weather and compatible survival mods. It keeps a bad situation difficult without making every sprint attempt instantly empty the bar."); emergencySprintReleaseStaminaPercentage = ((BaseUnityPlugin)this).Config.Bind<float>("Safety", "EmergencySprintReleaseStaminaPercentage", 0.22f, "After the minimum exhausted-jog time ends, sprinting is allowed again once stamina reaches this fraction even while exertion recovery continues. This prevents a long no-sprint lock while keeping escape costly."); enablePushStateMachine = ((BaseUnityPlugin)this).Config.Bind<bool>("Push State Machine", "Enabled", true, "Enables tap-driven Pushing, Adrenaline and fixed recovery states."); pushTapRatePerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "TapRatePerSecond", 3f, "E-key taps per second required to begin Pushing. Tune after playtesting. 4/sec proved too hard to sustain continuously for real players in practice."); pushTapSustainSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "TapSustainSeconds", 1.5f, "Continuous fast-tap duration required to enter Pushing."); pushTapGraceSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "TapGraceSeconds", 0.5f, "How long the fast-tap state survives after the per-second tap count last held. Absorbs single frame hitches (terrain loads, hard landings) that would otherwise expire several taps at once and eject the player from Pushing/Adrenaline build-up."); adrenalineContinuousTapSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "AdrenalineContinuousTapSeconds", 13.5f, "Continuous fast-tap duration from Pushing before Adrenaline begins."); pushSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "PushSpeedMultiplier", 1f, "Multiplier relative to normal sprint speed while Pushing. Minimum 1.0: tapping E must never slow normal sprinting. Adrenaline uses its separate multiplier."); adrenalineSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "AdrenalineSpeedMultiplier", 1.1f, "Final movement multiplier while Adrenaline is active."); adrenalineStaminaDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "AdrenalineStaminaDrainMultiplier", 0.5f, "Multiplier applied to Valheim's native sprint stamina drain for the full Adrenaline duration. 0.5 doubles effective stamina range."); eTapNativeStaminaCost = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "ETapNativeStaminaCost", 0.05f, "Extra native stamina points spent per accepted E tap while running. Recovery starts only when native stamina is zero."); adrenalineOnsetSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Adrenaline Sensory", "OnsetSeconds", 5f, "Duration of onset audio focus: game audio fades down by 70% and heartbeat_double.wav fades up to full volume. FOV follows the normal Adrenaline tier."); adrenalineOnsetFov = ((BaseUnityPlugin)this).Config.Bind<float>("Adrenaline Sensory", "OnsetFov", 45f, "Sharp tunnel FOV used during Adrenaline onset and when an enemy encounter fully re-tightens the tunnel."); adrenalineCombatRange = ((BaseUnityPlugin)this).Config.Bind<float>("Adrenaline Sensory", "CombatRange", 30f, "Maximum distance at which a faced monster counts as an Adrenaline combat encounter."); adrenalineFacingDotThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Adrenaline Sensory", "FacingDotThreshold", 0.35f, "Minimum forward-dot value required for a nearby monster to count as faced/engaged. 0.35 is roughly a 70 degree forward cone."); adrenalineHeartbeatBaselineBpm = ((BaseUnityPlugin)this).Config.Bind<float>("Adrenaline Sensory", "HeartbeatBaselineBPM", 124f, "Elevated baseline heartbeat throughout Adrenaline sustained phase."); adrenalineCombatHeartbeatMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Adrenaline Sensory", "CombatHeartbeatMultiplier", 1.25f, "Heartbeat multiplier during a faced combat encounter. 1.25 is the specified +25% spike."); adrenalineCombatDecayNearSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Adrenaline Sensory", "CombatDecayNearSeconds", 8f, "Slow-start then accelerating decay time after losing a nearby enemy encounter."); adrenalineCombatDecayFarSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Adrenaline Sensory", "CombatDecayFarSeconds", 2.5f, "Faster decay time once clear of nearby enemies."); pushStaminaDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "PushStaminaDrainMultiplier", 1f, "Normal native sprint drain while Pushing, plus ETapNativeStaminaCost per accepted E tap. Adrenaline has its separate drain multiplier."); if (Mathf.Abs(pushStaminaDrainMultiplier.Value - 0.5f) < 0.0001f) { pushStaminaDrainMultiplier.Value = 1f; } recoveryOneJogCapSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "RecoveryOneJogCapSeconds", 50f, "First phase of Pushing recovery. Walking/jogging allowed; sprint/push remain locked until all of Recovery One finishes."); recoveryOneBreathingTaperSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "RecoveryOneBreathingTaperSeconds", 30f, "Final breathing taper phase of Recovery One; sprint/push stay locked until this phase also completes."); recoveryTwoWalkOnlySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Push State Machine", "RecoveryTwoWalkOnlySeconds", 120f, "Adrenaline burnout duration during which jogging, sprinting and pushing are locked."); flatSlopeDrainBonus = ((BaseUnityPlugin)this).Config.Bind<float>("Terrain", "FlatSlopeDrainBonus", 0.0135f, "Flat stamina-drain bonus on any slope, replacing the previous angle-scaled slope drain."); exertionGainPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Exertion", "SprintExertionGainPerSecond", 1.5f, "Exertion gained per second while sprinting on neutral ground. A long hard run approaches high exertion."); exertionRecoveryPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Exertion", "RecoveryPerSecond", 2.5f, "Exertion removed per second while walking or resting. Recovery is intentionally slower than the old version so hard running has a believable after-effect."); stationaryRecoveryMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Exertion", "StationaryRecoveryMultiplier", 1.75f, "Extra exertion recovery while standing still. Resting should recover you faster than walking onward."); highExertionStart = ((BaseUnityPlugin)this).Config.Bind<float>("Exertion", "HighExertionStart", 35f, "Exertion percentage where heavy breathing, tunnel vision and late-run penalties begin building. V1.1.1 starts the feedback earlier so the player can feel effort building before complete exhaustion."); highExertionRunSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Exertion", "HighExertionRunSpeedMultiplier", 0.84f, "Minimum late-run speed multiplier at 100 exertion. Exhaustion should feel heavy, not like walking through glue."); highExertionDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Exertion", "HighExertionDrainMultiplier", 1.9f, "Additional stamina-drain multiplier reached at maximum exertion. Sustained hard running becomes less efficient instead of ending abruptly."); exhaustionTriggerStaminaPercentage = ((BaseUnityPlugin)this).Config.Bind<float>("Fatigue Recovery", "ExhaustionTriggerStaminaPercentage", 0.08f, "Stamina percentage threshold used after native stamina reaches zero. Remaining stamina never starts a recovery movement lock."); exhaustedJogSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Fatigue Recovery", "MinimumExhaustedJogSeconds", 5.5f, "Minimum number of seconds the player remains in a hard-jog recovery state after sprinting to near-zero stamina."); exhaustedJogSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Fatigue Recovery", "ExhaustedJogSpeedMultiplier", 0.88f, "Jog-speed multiplier during hard fatigue recovery."); recoveryStaminaPercentage = ((BaseUnityPlugin)this).Config.Bind<float>("Fatigue Recovery", "RecoveryStaminaPercentage", 0.28f, "Stamina percentage required before hard fatigue can end."); recoveryExertionPercentage = ((BaseUnityPlugin)this).Config.Bind<float>("Fatigue Recovery", "RecoveryExertionPercentage", 55f, "Exertion percentage required before hard fatigue can end. This gives exhaustion a believable recovery period after a long run."); enableHillEffects = ((BaseUnityPlugin)this).Config.Bind<bool>("Terrain", "EnableHillEffects", true, "Applies uphill and downhill movement/exertion effects using Valheim's real ground normal."); hillGraceAngle = ((BaseUnityPlugin)this).Config.Bind<float>("Terrain", "HillGraceAngle", 7f, "Slope angle in degrees before hill effects begin."); hillFullPenaltyAngle = ((BaseUnityPlugin)this).Config.Bind<float>("Terrain", "HillFullPenaltyAngle", 35f, "Slope angle in degrees where maximum hill effects apply."); uphillSpeedPenalty = ((BaseUnityPlugin)this).Config.Bind<float>("Terrain", "MaxUphillSpeedPenalty", 0.22f, "Maximum speed reduction while moving directly uphill on a steep slope."); uphillDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Terrain", "MaxUphillDrainMultiplier", 1.5f, "Maximum extra run stamina drain while moving directly uphill on a steep slope."); uphillExertionMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Terrain", "MaxUphillExertionMultiplier", 1.65f, "Maximum extra exertion build while moving directly uphill on a steep slope."); downhillSpeedBonus = ((BaseUnityPlugin)this).Config.Bind<float>("Terrain", "MaxDownhillSpeedBonus", 0.04f, "Maximum small speed bonus while moving directly downhill. Kept low to avoid unsafe runaway movement."); downhillDrainReduction = ((BaseUnityPlugin)this).Config.Bind<float>("Terrain", "MaxDownhillDrainReduction", 0.12f, "Maximum reduction in sprint stamina drain while moving directly downhill."); enableWeatherEffects = ((BaseUnityPlugin)this).Config.Bind<bool>("Weather", "EnableWeatherEffects", true, "Applies realistic movement and exertion effects for wet, cold and freezing conditions."); wetSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Weather", "WetSpeedMultiplier", 0.97f, "Movement multiplier while wet. Kept mild: wetness should make travel harder without feeling sticky."); wetDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Weather", "WetRunDrainMultiplier", 1.14f, "Sprint stamina-drain multiplier while wet."); wetExertionMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Weather", "WetExertionMultiplier", 1.16f, "Exertion-gain multiplier while wet."); coldDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Weather", "ColdRunDrainMultiplier", 1.08f, "Sprint stamina-drain multiplier in cold weather."); coldExertionMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Weather", "ColdExertionMultiplier", 1.1f, "Exertion-gain multiplier in cold weather."); freezingSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Weather", "FreezingSpeedMultiplier", 0.95f, "Movement multiplier in freezing conditions."); freezingDrainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Weather", "FreezingRunDrainMultiplier", 1.25f, "Sprint stamina-drain multiplier in freezing conditions."); freezingExertionMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Weather", "FreezingExertionMultiplier", 1.28f, "Exertion-gain multiplier in freezing conditions."); enableInjuryCompatibility = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "EnableYoureInjuredCompatibility", true, "Reads the installed You're Injured mod through safe reflection. It makes leg injuries build exertion faster and can apply its leg-speed penalty to Player overrides in current Valheim builds."); injuryExertionPenaltyStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Compatibility", "InjuryExertionPenaltyStrength", 0.85f, "How strongly leg injuries increase exertion. 0 disables the extra exertion link while preserving any direct injury speed effect."); applyInjurySpeedCompatibilityPenalty = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "ApplyYoureInjuredSpeedCompatibilityPenalty", true, "Applies the existing You're Injured leg-speed multiplier to Player movement. Leave true for current builds where the original injury speed patch targets Character instead of Player. Turn off only if a later You're Injured update already patches Player speed directly."); factorRefreshSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Compatibility", "FactorRefreshSeconds", 0.15f, "How often terrain, weather and optional-mod factors are refreshed. Lower values react faster; defaults are light on performance."); enableTunnelVision = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnableExhaustionTunnelVision", true, "Narrows peripheral vision progressively during sustained sprinting. The effect begins mild, then tightens and pulses more strongly as exertion builds toward exhaustion."); tunnelVisionStartExertion = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "TunnelVisionStartExertion", 8f, "Exertion percentage where a faint peripheral narrowing begins during a sustained run. The effect then builds continuously instead of appearing only at complete exhaustion."); tunnelVisionFullExertion = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "TunnelVisionFullExertion", 88f, "Exertion percentage where the tunnel effect reaches its intended maximum before hard exhaustion. Keep this below 100 so the player feels pressure before their stamina is empty."); maximumTunnelVisionAlpha = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "MaximumTunnelVisionAlpha", 0.68f, "Maximum edge opacity of the sprint-exhaustion tunnel vision. V1.1.4 narrows the clear centre more rather than simply making the whole screen darker."); tunnelVisionPulseStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "TunnelVisionPulseStrength", 0.3f, "How strongly the tunnel vision gently swells with heavy breathing. This only becomes noticeable as exertion rises."); tunnelVisionClearRadiusAtExhaustion = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "TunnelVisionClearRadiusAtExhaustion", 0.82f, "Size of the fully clear central view at heavy exhaustion. Lower values make the field of view feel more tightly narrowed; 0.82 keeps combat readable while making fatigue unmistakable."); enableWindRushStreaks = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnableWindRushStreaks", true, "Draws subtle pale wind streaks that burst outward from the centre toward all screen edges during a fresh full sprint. The centre remains clear for aiming and combat."); windRushStreakCount = ((BaseUnityPlugin)this).Config.Bind<int>("Visuals", "WindRushStreakCount", 28, "Number of radial wind streaks. Higher values create a fuller all-angle speed field but can feel visually busy."); windRushStartSprintBuild = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "WindRushStartSprintBuild", 0.52f, "Sprint build percentage at which wind streaks start. This keeps them out of normal jogging and the first moments of a run."); windRushMaximumAlpha = ((BaseUnityPlugin)this).Config.Bind<float>(new ConfigDefinition("Visuals", "WindRushMaximumAlpha"), 0.24f, new ConfigDescription("Brightness / visibility of individual wind streaks at full sprint. This is a slider in BepInEx Configuration Manager when that mod is installed. 0.24 is the current balanced default; try 0.32 for clearer streaks or 0.40 for a much stronger speed effect.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 0.65f), Array.Empty<object>())); windRushTravelSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "WindRushTravelSpeed", 1.35f, "How quickly radial wind streaks travel away from the screen centre at full sprint."); enableCameraSway = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnableCameraSway", true, "Adds subtle sprint bob and heavier breathing sway. It patches the final camera position so it layers after Survival View's Raised Head View."); cameraSwayClosestZoomOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "CameraSwayClosestZoomOnly", true, "When true, camera sway appears only at closest zoom / Survival View, avoiding unwanted third-person camera motion."); closestZoomTolerance = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "ClosestZoomToleranceMeters", 0.08f, "Tolerance used by CameraSwayClosestZoomOnly to recognise Valheim's closest normal third-person zoom."); sprintBobVerticalMeters = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "SprintBobVerticalMeters", 0.013f, "Maximum vertical camera bob while sprinting at low exertion. This is deliberately noticeable in Survival View without becoming nauseating."); sprintBobSideMeters = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "SprintBobSideMeters", 0.009f, "Maximum sideways camera bob while sprinting at low exertion."); fatigueBreathSwayMeters = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "FatigueBreathSwayMeters", 0.02f, "Maximum slow breathing sway at high exertion or hard fatigue recovery. This is intentionally small so it feels heavy rather than jittery."); sprintSwayFrequencyLow = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "SprintSwayFrequencyLowHz", 1.45f, "Slow sprint gait frequency in cycles per second. Lower values feel steadier and less jittery."); sprintSwayFrequencyHigh = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "SprintSwayFrequencyHighHz", 2.15f, "Fast sprint gait frequency in cycles per second at full pace."); breathSwayFrequencyLow = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "BreathSwayFrequencyLowHz", 0.2f, "Slow breathing sway frequency at the beginning of visible exertion."); breathSwayFrequencyHigh = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "BreathSwayFrequencyHighHz", 0.48f, "Heavy breathing sway frequency near exhaustion. 0.48 Hz is about 29 breaths per minute."); cameraSwaySmoothingSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "CameraSwaySmoothingSeconds", 0.2f, "How gently camera sway eases toward its target. Higher values are smoother and reduce jitter."); coolEdgeTintStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "CoolEdgeTintStrength", 0.68f, "How much the peripheral haze shifts toward an airy blue-grey before deepening toward charcoal near exhaustion."); enableNativeDepthOfField = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnableNativeDepthOfField", true, "Uses Valheim's own CameraEffects depth-of-field component during heavy exertion. It focuses on the object in the centre of the view and applies only a mild depth blur."); depthOfFieldClosestZoomOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "DepthOfFieldClosestZoomOnly", true, "When true, exhaustion depth of field only runs at closest zoom / Survival View to keep normal third-person gameplay clear."); depthOfFieldStartVisualIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "DepthOfFieldStartVisualIntensity", 0.34f, "Visual-exhaustion intensity where mild focus blur begins. Tunnel tint can start earlier, but focus blur waits until exertion is meaningful."); depthOfFieldMaximumBlurSize = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "DepthOfFieldMaximumBlurSize", 0.55f, "Maximum native depth-of-field blur size near exhaustion. Kept deliberately modest so the screen centre remains usable in combat."); depthOfFieldFocalSizeAtExhaustion = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "DepthOfFieldFocalSizeAtExhaustion", 1.1f, "Focal range around the point you are looking at near exhaustion. Smaller values create a narrower, more focused view."); depthOfFieldFallbackFocusDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "DepthOfFieldFallbackFocusDistance", 18f, "Focus distance used when the centre camera ray does not hit terrain or an object."); depthOfFieldMaximumFocusDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "DepthOfFieldMaximumFocusDistance", 80f, "Maximum centre-view ray distance used for exhaustion focus."); flowStateBaseFov = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "FlowStateBaseFov", 60f, "Resting FOV floor. Realistic Running never drives FOV below this value."); flowStateMaximumFov = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "FlowStateMaximumFov", 70f, "FOV reached as a healthy run settles into flow. This replaces the retired SprintFovBoostDegrees setting."); pushStateFov = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "PushStateFov", 80f, "FOV reached during E-tap Pushing."); adrenalineStateFov = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "AdrenalineStateFov", 85f, "FOV reached during automatic Adrenaline."); visualTierTransitionSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "VisualTierTransitionSeconds", 1f, "Exact seconds for each transition in both directions, starting at the currently visible FOV. All tier-based effects share this transition."); adrenalineAudioFadeSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Adrenaline Sensory", "AudioFadeSeconds", 0.8f, "Smooth fade into and out of onset audio: game audio falls by 70% while the heartbeat rises to full clip volume."); exertionVisualTimeConstantSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "ExertionVisualTimeConstantSeconds", 3f, "Single exponential time constant shared by FOV, saturation, clarity, wind rush and peripheral motion blur. Applies equally as exertion rises and falls."); enableControlledMotionBlur = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnableControlledMotionBlur", true, "Enables masked radial scene blur in the wind-rush clear-centre zone, scaled by the shared exertion visual value. Native full-frame motion blur stays disabled."); enableFlowColorSaturation = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnableFlowColorSaturation", true, "Adds modest saturation from the same exertion-driven flow value as FOV and speed cues."); flowSaturationMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "FlowSaturationMultiplier", 1.2f, "A restrained realistic saturation multiplier at full Adrenaline visuals. Flow and Pushing use proportionally less; neutral is 1.0."); enableFlowClarity = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnableFlowClarity", true, "Subtle clarity from the shared smoothed exertion visual value."); flowClarityStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "FlowClarityStrength", 0.12f, "Conservative sharpening strength at full exertion visuals (0-0.25)."); peripheralMotionBlurStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "PeripheralMotionBlurStrength", 0.05f, "Radial blur sample distance at full exertion visuals (0-0.08). Always zero inside the wind-rush clear centre."); enablePeripheralMotionAwareness = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnablePeripheralMotionAwareness", false, "Optional experimental camera-compensated moving silhouette contrast preservation. Disabled by default to retain the proven rendering. No creature recognition or fine-detail sharpening; does not undo native DOF."); peripheralMotionAwarenessStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "PeripheralMotionAwarenessStrength", 0.65f, "Moving broad-contrast preservation strength (0-1). Applies only outside the existing clear centre; stationary scenery is not intentionally enhanced."); enablePeripheralBlurOverlay = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnablePeripheralBlurOverlay", true, "Adds a soft blue-grey focus-softening overlay around the outer edge as exertion builds. It complements Valheim's native depth of field without obscuring the centre."); peripheralBlurStartIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "PeripheralBlurStartIntensity", 0.22f, "Visual-exhaustion intensity where the subtle peripheral blur overlay begins to appear."); peripheralBlurMaximumAlpha = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "PeripheralBlurMaximumAlpha", 0.24f, "Maximum opacity of the soft peripheral blur overlay near heavy exhaustion."); peripheralBlurClearRadiusAtExhaustion = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "PeripheralBlurClearRadiusAtExhaustion", 0.92f, "Clear central radius that remains crisp when the peripheral blur overlay is at maximum strength. Lower values create more outer-edge focus loss."); enableExhaustionHeartbeat = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "EnableExhaustionHeartbeat", true, "Plays the supplied double-heartbeat sample as physical exhaustion builds, then spaces the beats out and fades them during recovery."); heartbeatStartPressure = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "HeartbeatStartPressure", 0.42f, "Exhaustion pressure where the heartbeat first becomes audible. It remains silent during ordinary jogging and light sprinting."); heartbeatRecoveryBpm = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "HeartbeatRecoveryBPM", 88f, "Slowest audible heartbeat rate during the tail end of recovery."); heartbeatMaximumBpm = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "HeartbeatMaximumBPM", 150f, "Fastest heartbeat rate at hard exhaustion. Values above 160 tend to feel artificial with this double-beat sample."); heartbeatMaximumVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "HeartbeatMaximumVolume", 0.3f, "Maximum heartbeat volume at hard exhaustion. Keep low enough that Valheim combat, rain and music still remain audible."); heartbeatIntensitySmoothingSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "HeartbeatIntensitySmoothingSeconds", 0.75f, "How gently the heartbeat rate responds to changing exhaustion. This prevents abrupt BPM jumps when you stop running."); enableBloodPulse = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "EnableBloodPulse", true, "Layers a soft, low pressure whoosh swell under the heartbeat thump, plus a faint synced screen-edge pulse. Rides on the existing heartbeat pressure/BPM value; not an independent system."); bloodPulseMinVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "BloodPulseMinVolume", 0.035f, "Whoosh volume at rest, riding under the heartbeat."); bloodPulseMaxVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "BloodPulseMaxVolume", 0.35f, "Whoosh volume at full adrenaline pressure. Always kept well below the heartbeat clip's own peak volume so it never competes with the thump."); bloodPulseVignetteMaxAlpha = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "BloodPulseVignetteMaxAlpha", 0.1f, "Maximum opacity of the subtle screen-edge brightness/darkness pulse timed to the heartbeat. Near-subliminal at rest, only clearly perceptible under real exertion or adrenaline."); enableMovementAudio = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "EnableMovementAudio", true, "Plays the supplied breathing and footstep layers alongside Valheim's native surface sounds."); shallowBreathVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "ShallowBreathVolume", 0.18f, "Volume of Shallow_Breath.wav at run start."); flowBreathVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "FlowBreathVolume", 0.16f, "Volume of Medium_Flow_Breathing.wav during a settled run."); heavyBreathVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "HeavyBreathVolume", 0.28f, "Volume of Breathing_Heavy.wav on hills, Pushing and Adrenaline."); stompFootstepVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "StompFootstepVolume", 0.16f, "Volume of Stomps_Footsteps.wav during the initial run phase."); runStartAudioSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "RunStartAudioSeconds", 15f, "Initial stomp-footstep phase length. Normal breathing and flow visuals use exertion thresholds instead."); movementAudioCrossfadeSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "MovementAudioCrossfadeSeconds", 0.8f, "Smooth breathing/footstep transitions in seconds (0 disables fading, maximum 3). Outgoing clips stop when their fade finishes; run phase timing stays unchanged."); enableBaselineExhaustionBreathing = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "EnableBaselineExhaustionBreathing", true, "Plays abrupt gasping heavy breathing when normal sprint stamina hits the exhaustion threshold."); exhaustionBreathRestRecoverySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "ExhaustionBreathRestRecoverySeconds", 60f, "Baseline exhaustion breathing reaches calm after this many seconds while standing or walking."); exhaustionBreathJogRecoverySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "ExhaustionBreathJogRecoverySeconds", 120f, "Baseline exhaustion breathing reaches calm after this many seconds while exhausted and continuing to jog."); exhaustionBreathInitialVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "ExhaustionBreathInitialVolume", 0.42f, "Immediate heavy-breath volume when normal sprint exhaustion begins."); exhaustionBreathInitialPitch = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "ExhaustionBreathInitialPitch", 1.15f, "Initial heavy-breath clip pitch. The gasp rate itself slows through timed retriggers during recovery."); showRecoverySeconds = ((BaseUnityPlugin)this).Config.Bind<bool>("Interface", "ShowRecoverySeconds", false, "Shows the remaining recovery seconds beside the red recovery bar. Off by default."); } private void MigratePerceptibilityDefaults() { bool flag = false; if (Mathf.Abs(sprintStartSpeedFraction.Value - 0.78f) < 0.001f) { sprintStartSpeedFraction.Value = 0.72f; flag = true; } if (Mathf.Abs(topSprintSpeedMultiplier.Value - 1.2f) < 0.001f || Mathf.Abs(topSprintSpeedMultiplier.Value - 1.32f) < 0.001f) { topSprintSpeedMultiplier.Value = 1.45f; flag = true; } if (Mathf.Abs(highExertionStart.Value - 55f) < 0.001f) { highExertionStart.Value = 35f; flag = true; } if (Mathf.Abs(highExertionRunSpeedMultiplier.Value - 0.89f) < 0.001f) { highExertionRunSpeedMultiplier.Value = 0.84f; flag = true; } if (Mathf.Abs(exhaustionTriggerStaminaPercentage.Value - 0.02f) < 0.001f) { exhaustionTriggerStaminaPercentage.Value = 0.08f; flag = true; } if (Mathf.Abs(maximumTunnelVisionAlpha.Value - 0.42f) < 0.001f || Mathf.Abs(maximumTunnelVisionAlpha.Value - 0.58f) < 0.001f) { maximumTunnelVisionAlpha.Value = 0.78f; flag = true; } if (Mathf.Abs(sprintBobVerticalMeters.Value - 0.018f) < 0.001f) { sprintBobVerticalMeters.Value = 0.032f; flag = true; } if (Mathf.Abs(sprintBobSideMeters.Value - 0.012f) < 0.001f) { sprintBobSideMeters.Value = 0.022f; flag = true; } if (Mathf.Abs(fatigueBreathSwayMeters.Value - 0.032f) < 0.001f) { fatigueBreathSwayMeters.Value = 0.02f; flag = true; } if (Mathf.Abs(sprintBobVerticalMeters.Value - 0.032f) < 0.001f) { sprintBobVerticalMeters.Value = 0.013f; flag = true; } if (Mathf.Abs(sprintBobSideMeters.Value - 0.022f) < 0.001f) { sprintBobSideMeters.Value = 0.009f; flag = true; } if (Mathf.Abs(fatigueBreathSwayMeters.Value - 0.058f) < 0.001f) { fatigueBreathSwayMeters.Value = 0.02f; flag = true; } if (Mathf.Abs(maximumTunnelVisionAlpha.Value - 0.78f) < 0.001f || Mathf.Abs(maximumTunnelVisionAlpha.Value - 0.62f) < 0.001f) { maximumTunnelVisionAlpha.Value = 0.68f; flag = true; } if (Mathf.Abs(coolEdgeTintStrength.Value - 0.62f) < 0.001f) { coolEdgeTintStrength.Value = 0.68f; flag = true; } if (Mathf.Abs(depthOfFieldStartVisualIntensity.Value - 0.34f) < 0.001f) { depthOfFieldStartVisualIntensity.Value = 0.26f; flag = true; } if (Mathf.Abs(depthOfFieldMaximumBlurSize.Value - 0.55f) < 0.001f) { depthOfFieldMaximumBlurSize.Value = 0.7f; flag = true; } if (Mathf.Abs(depthOfFieldFocalSizeAtExhaustion.Value - 1.1f) < 0.001f) { depthOfFieldFocalSizeAtExhaustion.Value = 0.9f; flag = true; } if (windRushStreakCount.Value == 12) { windRushStreakCount.Value = 28; flag = true; } if (Mathf.Abs(windRushMaximumAlpha.Value - 0.2f) < 0.001f) { windRushMaximumAlpha.Value = 0.24f; flag = true; } if (flag) { ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Realistic Running: migrated untouched defaults to V1.1.8 slightly clearer radial wind-rush streaks."); } } private void MigrateEscapeSafetyDefaults() { if (Mathf.Abs(exhaustedJogSeconds.Value - 8f) < 0.001f && Mathf.Abs(exhaustedJogSpeedMultiplier.Value - 0.84f) < 0.001f && Mathf.Abs(recoveryStaminaPercentage.Value - 0.38f) < 0.001f && Mathf.Abs(recoveryExertionPercentage.Value - 45f) < 0.001f) { exhaustedJogSeconds.Value = 5.5f; exhaustedJogSpeedMultiplier.Value = 0.88f; recoveryStaminaPercentage.Value = 0.28f; recoveryExertionPercentage.Value = 55f; ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Realistic Running: migrated the exhausted-sprint recovery defaults to the ground-floor escape safety values."); } } private void MigratePushStateDefaults() { bool flag = false; if (Mathf.Abs(adrenalineOnsetSeconds.Value - 7f) < 0.001f) { adrenalineOnsetSeconds.Value = 5f; flag = true; } if (Mathf.Abs(pushTapSustainSeconds.Value - 0.5f) < 0.001f) { pushTapSustainSeconds.Value = 1.5f; flag = true; } if (Mathf.Abs(pushTapRatePerSecond.Value - 4f) < 0.001f) { pushTapRatePerSecond.Value = 3f; flag = true; } if (Mathf.Abs(adrenalineSpeedMultiplier.Value - 5.5f) < 0.001f || Mathf.Abs(adrenalineSpeedMultiplier.Value - 4.7f) < 0.001f || Mathf.Abs(adrenalineSpeedMultiplier.Value - 4.9f) < 0.001f || Mathf.Abs(adrenalineSpeedMultiplier.Value - 3.3f) < 0.001f || Mathf.Abs(adrenalineSpeedMultiplier.Value - 2.7f) < 0.001f || Mathf.Abs(adrenalineSpeedMultiplier.Value - 2.4f) < 0.001f) { adrenalineSpeedMultiplier.Value = 2.1f; flag = true; } if (Mathf.Abs(adrenalineSpeedMultiplier.Value - 2.1f) < 0.001f) { adrenalineSpeedMultiplier.Value = 1.1f; flag = true; } if (Mathf.Abs(adrenalineSpeedMultiplier.Value - 1.5f) < 0.001f) { adrenalineSpeedMultiplier.Value = 1.1f; flag = true; } if (Mathf.Abs(pushSpeedMultiplier.Value - 2.5f) < 0.001f || Mathf.Abs(pushSpeedMultiplier.Value - 1.5f) < 0.001f || pushSpeedMultiplier.Value < 1f) { pushSpeedMultiplier.Value = 1f; flag = true; } if (flag) { ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Realistic Running: migrated the push-state defaults."); } } private void MigrateFlowFovDefaults() { bool flag = false; if (Mathf.Abs(pushStateFov.Value - 77f) < 0.001f) { pushStateFov.Value = 80f; flag = true; } if (Mathf.Abs(adrenalineStateFov.Value - 83f) < 0.001f) { adrenalineStateFov.Value = 85f; flag = true; } if (Mathf.Abs(visualTierTransitionSeconds.Value - 4.5f) < 0.001f || Mathf.Abs(visualTierTransitionSeconds.Value - 3.5f) < 0.001f) { visualTierTransitionSeconds.Value = 1f; flag = true; } if (Mathf.Abs(flowSaturationMultiplier.Value - 1.15f) < 0.001f || Mathf.Abs(flowSaturationMultiplier.Value - 1.25f) < 0.001f) { flowSaturationMultiplier.Value = 1.2f; flag = true; } if (Mathf.Abs(peripheralMotionBlurStrength.Value - 0.018f) < 0.0001f) { peripheralMotionBlurStrength.Value = 0.05f; flag = true; } if (Mathf.Abs(flowStateMaximumFov.Value - 75f) < 0.001f) { flowStateMaximumFov.Value = 70f; flag = true; } if (flag) { ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Realistic Running: migrated untouched flow visual defaults to the restrained staged running profile."); } } private void MigrateMovementAudioDefaults() { if (Mathf.Abs(runStartAudioSeconds.Value - 2f) < 0.001f || Mathf.Abs(runStartAudioSeconds.Value - 7.5f) < 0.001f) { runStartAudioSeconds.Value = 15f; ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Realistic Running: migrated the shallow-breath phase to 15 seconds."); } } private void InstallPatches() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Expected O, but got Unknown //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Expected O, but got Unknown //IL_019b: Expected O, but got Unknown //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Expected O, but got Unknown //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Expected O, but got Unknown //IL_0233: Expected O, but got Unknown //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Expected O, but got Unknown //IL_02f8: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Expected O, but got Unknown //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_0324: Expected O, but got Unknown //IL_03a8: Unknown result type (might be due to invalid IL or missing references) //IL_03b9: Expected O, but got Unknown harmony = new Harmony("com.marccunningham.survivalmovementexertion"); HarmonyMethod val = new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerSetControlsPrefix", (Type[])null); val.priority = 0; val.after = new string[1] { "com.marccunningham.survivalview" }; setControlsPatchInstalled = TryPatch(FindMethod(typeof(Player), "SetControls", null), val, null, null, "Player.SetControls(...)"); HarmonyMethod val2 = new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerGetJogSpeedFactorPostfix", (Type[])null); val2.priority = 0; jogSpeedPatchInstalled = TryPatch(FindMethod(typeof(Player), "GetJogSpeedFactor", Type.EmptyTypes), null, val2, null, "Player.GetJogSpeedFactor()"); HarmonyMethod val3 = new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerGetRunSpeedFactorPostfix", (Type[])null); val3.priority = 0; runSpeedPatchInstalled = TryPatch(FindMethod(typeof(Player), "GetRunSpeedFactor", Type.EmptyTypes), null, val3, null, "Player.GetRunSpeedFactor()"); HarmonyMethod val4 = new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerCheckRunPostfix", (Type[])null); val4.priority = 0; val4.after = new string[1] { "com.marccunningham.survivalview" }; checkRunPatchInstalled = TryPatch(FindMethod(typeof(Player), "CheckRun", new Type[2] { typeof(Vector3), typeof(float) }), new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerCheckRunPrefix", (Type[])null), val4, new HarmonyMethod(typeof(SurvivalMovementPatches), "PlayerCheckRunFinalizer", (Type[])null), "Player.CheckRun(Vector3, float)"); HarmonyMethod val5 = new HarmonyMethod(typeof(SurvivalMovementPatches), "CharacterUpdateWalkingPrefix", (Type[])null); val5.priority = 0; val5.after = new string[1] { "com.marccunningham.survivalview" }; recoveryWalkingPatchInstalled = TryPatch(FindMethod(typeof(Character), "UpdateWalking", new Type[1] { typeof(float) }), val5, new HarmonyMethod(typeof(SurvivalMovementPatches), "CharacterUpdateWalkingPostfix", (Type[])null), new HarmonyMethod(typeof(SurvivalMovementPatches), "CharacterUpdateWalkingFinalizer", (Type[])null), "Character.UpdateWalking(float) recovery enforcement"); HarmonyMethod val6 = new HarmonyMethod(typeof(SurvivalMovementPatches), "GameCameraGetCameraPositionPostfix", (Type[])null); val6.priority = 0; val6.after = new string[1] { "com.marccunningham.survivalview" }; cameraPositionPatchInstalled = TryPatch(FindMethod(typeof(GameCamera), "GetCameraPosition", new Type[3] { typeof(float), typeof(Vector3).MakeByRefType(), typeof(Quaternion).MakeByRefType() }), null, val6, null, "GameCamera.GetCameraPosition(float, out Vector3, out Quaternion)"); depthOfFieldPatchInstalled = TryPatch(FindMethod(typeof(CameraEffects), "UpdateDOF", Type.EmptyTypes), null, new HarmonyMethod(typeof(SurvivalMovementPatches), "CameraEffectsUpdateDofPostfix", (Type[])null), null, "CameraEffects.UpdateDOF()"); HarmonyMethod val7 = new HarmonyMethod(typeof(SurvivalMovementPatches), "GameCameraUpdateCameraFovPostfix", (Type[])null); val7.priority = 0; val7.after = new string[1] { "com.marccunningham.survivalview" }; cameraFovPatchInstalled = TryPatch(FindMethod(typeof(GameCamera), "UpdateCamera", new Type[1] { typeof(float) }), null, val7, null, "GameCamera.UpdateCamera(float) FOV authority"); cameraFovSourcePatchInstalled = TryPatch(FindMethod(typeof(GameCamera), "UpdateFOV", Type.EmptyTypes), new HarmonyMethod(typeof(SurvivalMovementPatches), "GameCameraUpdateFovPrefix", (Type[])null), null, null, "GameCamera.UpdateFOV() shared tier authority"); cameraFovLatePatchInstalled = TryPatch(FindMethod(typeof(GameCamera), "LateUpdate", Type.EmptyTypes), null, val7, null, "GameCamera.LateUpdate() final FOV authority"); } private bool TryPatch(MethodInfo target, HarmonyMethod prefix, HarmonyMethod postfix, HarmonyMethod finalizer, string targetName) { if (target == null) { ((BaseUnityPlugin)this).Logger.LogError((object)("Realistic Running: could not find " + targetName + ". That feature is disabled.")); return false; } try { harmony.Patch((MethodBase)target, prefix, postfix, (HarmonyMethod)null, finalizer, (HarmonyMethod)null); LogVerbose("Realistic Running: patched " + targetName + "."); return true; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Realistic Running: failed to patch " + targetName + ": " + ex)); return false; } } private bool HasSurvivalViewAuthority() { return modEnabled != null && modEnabled.Value; } private void TryClaimSurvivalViewAuthority() { if (survivalViewAuthorityClaimed) { return; } Type type = Type.GetType("SurvivalView.SurvivalViewBridge, SurvivalView", throwOnError: false); if (type == null) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (string.Equals(assembly.GetName().Name, "SurvivalView", StringComparison.OrdinalIgnoreCase)) { type = assembly.GetType("SurvivalView.SurvivalViewBridge", throwOnError: false); if (type != null) { break; } } } } if (type == null) { return; } FieldInfo field = type.GetField("ExternalFovAuthority", BindingFlags.Static | BindingFlags.Public); FieldInfo field2 = type.GetField("ExternalMovementAuthority", BindingFlags.Static | BindingFlags.Public); if (field == null || field2 == null || field.FieldType != typeof(Func<bool>) || field2.FieldType != typeof(Func<bool>)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Realistic Running: Survival View bridge has an unsupported authority contract."); return; } try { Delegate value = Delegate.CreateDelegate(typeof(Func<bool>), this, "HasSurvivalViewAuthority"); field.SetValue(null, value); field2.SetValue(null, value); survivalViewExternalFovAuthorityField = field; survivalViewExternalMovementAuthorityField = field2; survivalViewAuthorityDelegate = value; survivalViewAuthorityClaimed = true; LogVerbose("Realistic Running: claimed Survival View FOV and movement authority through its optional bridge."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Realistic Running: could not claim Survival View authority: " + ex.Message)); } } private void ReleaseSurvivalViewAuthority() { if (!survivalViewAuthorityClaimed) { return; } try { if (survivalViewExternalFovAuthorityField != null && object.Equals(survivalViewExternalFovAuthorityField.GetValue(null), survivalViewAuthorityDelegate)) { survivalViewExternalFovAuthorityField.SetValue(null, null); } if (survivalViewExternalMovementAuthorityField != null && object.Equals(survivalViewExternalMovementAuthorityField.GetValue(null), survivalViewAuthorityDelegate)) { survivalViewExternalMovementAuthorityField.SetValue(null, null); } } catch { } finally { survivalViewExternalFovAuthorityField = null; survivalViewExternalMovementAuthorityField = null; survivalViewAuthorityDelegate = null; survivalViewAuthorityClaimed = false; } } private static MethodInfo FindMethod(Type type, string methodName, Type[] parameterTypes) { if (parameterTypes != null) { return type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null); } MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < methods.Length; i++) { if (methods[i].Name == methodName) { return methods[i]; } } return null; } private bool IsMovementEligible(Player player) { return modEnabled.Value && (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer && !((Character)player).IsDead() && !((Character)player).IsAttached() && !((Character)player).IsSwimming() && !((Character)player).IsFlying(); } private void ResetTransientMovementState() { visualInputPlayer = null; visualRawMovementRequested = (visualSprintRequested = false); Player localPlayer = Player.m_localPlayer; bool flag = (Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead(); smoothedInputMagnitude = Mathf.MoveTowards(smoothedInputMagnitude, 0f, Time.deltaTime * 5f); sprintBuild = Mathf.MoveTowards(sprintBuild, 0f, Time.deltaTime * 4f); exertion = Mathf.MoveTowards(exertion, 0f, Time.deltaTime * Mathf.Max(0f, exertionRecoveryPerSecond.Value)); wasSprinting = false; if (flag) { exhaustedJogRemaining = 0f; fatigueRecoveryActive = false; baselineMovementRecoveryActive = false; pushState = PushState.Normal; pushStateRemaining = 0f; pushMovementRecoveryActive = false; pushMinimumRecoveryRemaining = 0f; tapTimes.Clear(); fastTapStartedAt = -1f; lastFastTapSatisfiedTime = -1f; lastObservedStaminaForAdrenalineRefund = -1f; pushStateLoaded = false; pushStateSaveTimer = 0f; baselineExhaustionBreathingActive = false; baselineExhaustionBreathingCompleted = false; baselineExhaustionBreathingProgress = 0f; baselineSprintAttemptWasHeld = false; baselineExhaustionBreathingStatus = "idle"; } cachedClimbingSlope = false; movementAudioSequence.Reset(); lastRunDrainMultiplier = 1f; smoothedCameraSwayVertical = 0f; smoothedCameraSwaySide = 0f; cameraSwayVerticalVelocity = 0f; cameraSwaySideVelocity = 0f; latestCameraDistance = float.MaxValue; latestCameraMinimumDistance = float.MaxValue; heartbeatCurrentPressure = 0f; heartbeatPressureVelocity = 0f; heartbeatCurrentBpm = 0f; heartbeatNextBeatTime = Time.unscaledTime + 0.1f; lastHeartbeatBeatTime = -999f; bloodPulseVignetteAlpha = 0f; StopHeartbeatAudio(); StopBloodPulseAudio(); StopMovementAudio(); ResetWorldFactors(); } private void ResetWorldFactors() { terrainSpeedMultiplier = 1f; terrainDrainMultiplier = 1f; terrainExertionMultiplier = 1f; weatherSpeedMultiplier = 1f; weatherDrainMultiplier = 1f; weatherExertionMultiplier = 1f; weatherRecoveryMultiplier = 1f; injurySpeedMultiplier = 1f; injuryExertionMultiplier = 1f; cachedSlopeAngle = 0f; cachedWet = false; cachedCold = false; cachedFreezing = false; } private void RefreshWorldFactors(Player player) { UpdateTerrainFactors(player); UpdateWeatherFactors(player); UpdateInjuryCompatibility(player); } private void UpdateTerrainFactors(Player player) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) terrainSpeedMultiplier = 1f; terrainDrainMultiplier = 1f; terrainExertionMultiplier = 1f; cachedSlopeAngle = 0f; cachedClimbingSlope = false; if (!enableHillEffects.Value || !((Character)player).IsOnGround()) { return; } Vector3 moveDir = ((Character)player).GetMoveDir(); moveDir.y = 0f; if (((Vector3)(ref moveDir)).sqrMagnitude <= 1.0000001E-06f) { return; } Vector3 lastGroundNormal = ((Character)player).GetLastGroundNormal(); if (((Vector3)(ref lastGroundNormal)).sqrMagnitude <= 0.01f) { return; } ((Vector3)(ref lastGroundNormal)).Normalize(); cachedSlopeAngle = Vector3.Angle(lastGroundNormal, Vector3.up); if (!(cachedSlopeAngle <= 0.01f)) { Vector3 val = Vector3.ProjectOnPlane(Vector3.up, lastGroundNormal); if (!(((Vector3)(ref val)).sqrMagnitude <= 0.0001f)) { ((Vector3)(ref val)).Normalize(); float num = Vector3.Dot(((Vector3)(ref moveDir)).normalized, val); cachedClimbingSlope = num > 0.01f; terrainDrainMultiplier = 1f + Mathf.Clamp(flatSlopeDrainBonus.Value, 0f, 0.5f); } } } private void UpdateWeatherFactors(Player player) { weatherSpeedMultiplier = 1f; weatherDrainMultiplier = 1f; weatherExertionMultiplier = 1f; weatherRecoveryMultiplier = 1f; cachedWet = false; cachedCold = false; cachedFreezing = false; if (enableWeatherEffects.Value) { SEMan sEMan = ((Character)player).GetSEMan(); bool flag = sEMan != null && sEMan.HaveStatusEffect(SEMan.s_statusEffectWet); cachedWet = flag || EnvMan.IsWet(); cachedFreezing = EnvMan.IsFreezing(); cachedCold = !cachedFreezing && EnvMan.IsCold(); if (cachedWet) { weatherSpeedMultiplier *= Mathf.Clamp(wetSpeedMultiplier.Value, 0.7f, 1f); weatherDrainMultiplier *= Mathf.Max(1f, wetDrainMultiplier.Value); weatherExertionMultiplier *= Mathf.Max(1f, wetExertionMultiplier.Value); weatherRecoveryMultiplier *= 0.85f; } if (cachedFreezing) { weatherSpeedMultiplier *= Mathf.Clamp(freezingSpeedMultiplier.Value, 0.7f, 1f); weatherDrainMultiplier *= Mathf.Max(1f, freezingDrainMultiplier.Value); weatherExertionMultiplier *= Mathf.Max(1f, freezingExertionMultiplier.Value); weatherRecoveryMultiplier *= 0.72f; } else if (cachedCold) { weatherDrainMultiplier *= Mathf.Max(1f, coldDrainMultiplier.Value); weatherExertionMultiplier *= Mathf.Max(1f, coldExertionMultiplier.Value); weatherRecoveryMultiplier *= 0.88f; } } } private void UpdateInjuryCompatibility(Player player) { injurySpeedMultiplier = 1f; injuryExertionMultiplier = 1f; if (!enableInjuryCompatibility.Value) { return; } ResolveInjuryReflection(); if (!injuryReflectionUsable) { return; } try { object value = injuryInstanceField.GetValue(null); if (value != null && (bool)injuryIsActiveForMethod.Invoke(value, new object[1] { player })) { float num = Mathf.Clamp((float)injuryRunSpeedMultiplierMethod.Invoke(value, null), 0.3f, 1f); if (applyInjurySpeedCompatibilityPenalty.Value) { injurySpeedMultiplier = num; } float num2 = 1f - num; injuryExertionMultiplier = 1f + num2 * Mathf.Max(0f, injuryExertionPenaltyStrength.Value); } } catch { injuryReflectionUsable = false; injurySpeedMultiplier = 1f; injuryExertionMultiplier = 1f; } } private void ResolveInjuryReflection() { if (injuryReflectionUsable) { return; } if (injuryPluginType == null) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType("YoureInjured.YoureInjuredPlugin"); if (type != null) { injuryPluginType = type; break; } } } if (!(injuryPluginType == null)) { injuryInstanceField = injuryPluginType.GetField("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); injuryIsActiveForMethod = injuryPluginType.GetMethod("IsActiveFor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Player) }, null); injuryRunSpeedMultiplierMethod = injuryPluginType.GetMethod("GetRunSpeedMultiplier", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); injuryReflectionUsable = injuryInstanceField != null && injuryIsActiveForMethod != null && injuryRunSpeedMultiplierMethod != null; } } private void TryLoadHeartbeatAudio() { if (!enableExhaustionHeartbeat.Value) { heartbeatStatus = "disabled in config"; return; } try { string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); if (string.IsNullOrEmpty(directoryName)) { heartbeatStatus = "plugin folder could not be resolved"; return; } string[] array = new string[4] { Path.Combine(directoryName, "assets", "heartbeat_double.wav"), Path.Combine(directoryName, "heartbeat_double.wav"), Path.Combine(directoryName, "assets", "untitled.wav"), Path.Combine(directoryName, "untitled.wav") }; string text = null; for (int i = 0; i < array.Length; i++) { if (File.Exists(array[i])) { text = array[i]; break; } } if (string.IsNullOrEmpty(text)) { heartbeatStatus = "missing assets/heartbeat_double.wav"; return; } if (!TryReadWaveFile(text, out var samples, out var channels, out var sampleRate, out var status)) { heartbeatStatus = "could not decode WAV: " + status; return; } Type type = FindLoadedType("UnityEngine.AudioClip"); Type type2 = FindLoadedType("UnityEngine.AudioSource"); if (type == null || type2 == null) { heartbeatStatus = "Unity audio types were unavailable"; return; } MethodInfo method = type.GetMethod("Create", BindingFlags.Static | BindingFlags.Public, null, new Type[5] { typeof(string), typeof(int), typeof(int), typeof(int), typeof(bool) }, null); MethodInfo method2 = type.GetMethod("SetData", BindingFlags.Instance | BindingFlags.Public, null, new Type[2] { typeof(float[]), typeof(int) }, null); if (method == null || method2 == null) { heartbeatStatus = "Unity AudioClip methods were unavailable"; return; } int num = samples.Length / Mathf.Max(1, channels); object obj = method.Invoke(null, new object[5] { "SurvivalMovementExertion_Heartbeat", num, channels, sampleRate, false }); if (obj == null) { heartbeatStatus = "Unity could not create the heartbeat clip"; return; } if (!(bool)method2.Invoke(obj, new object[2] { samples, 0 })) { Object.Destroy((Object)((obj is Object) ? obj : null)); heartbeatStatus = "Unity rejected the heartbeat sample data"; return; } Component val = ((Component)this).gameObject.AddComponent(type2); if ((Object)(object)val == (Object)null) { Object.Destroy((Object)((obj is Object) ? obj : null)); heartbeatStatus = "Unity could not create the heartbeat audio source"; return; } SetNumericProperty(type2, val, "spatialBlend", 0f); SetBooleanProperty(type2, val, "loop", value: false); SetBooleanProperty(type2, val, "playOnAwake", value: false); SetNumericProperty(type2, val, "volume", 1f); MethodInfo method3 = type2.GetMethod("PlayOneShot", BindingFlags.Instance | BindingFlags.Public, null, new Type[2] { type, typeof(float) }, null); MethodInfo method4 = type2.GetMethod("Stop", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null); if (method3 == null) { Object.Destroy((Object)(object)val); Object.Destroy((Object)((obj is Object) ? obj : null)); heartbeatStatus = "Unity AudioSource.PlayOneShot was unavailable"; return; } heartbeatAudioSource = val; heartbeatClip = (Object)((obj is Object) ? obj : null); heartbeatPlayOneShotMethod = method3; heartbeatStopMethod = method4; heartbeatAssetPath = text; heartbeatNextBeatTime = Time.unscaledTime + 0.2f; heartbeatStatus = "ready " + sampleRate + " Hz, " + channels + " channel(s), " + num + " frames"; } catch (Exception ex) { heartbeatStatus = "load exception: " + ex.GetType().Name; } } private void TryLoadBloodPulseAudio() { if (!enableBloodPulse.Value) { bloodPulseStatus = "disabled in config"; return; } try { string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); if (string.IsNullOrEmpty(directoryName)) { bloodPulseStatus = "plugin folder could not be resolved"; return; } string[] array = new string[3] { Path.Combine(directoryName, "assets", "Whoosh_Effect.wav"), Path.Combine(directoryName, "Whoosh_Effect.wav"), Path.Combine(directoryName, "NEW SFX", "Whoosh_Effect.wav") }; string text = null; for (int i = 0; i < array.Length; i++) { if (File.Exists(array[i])) { text = array[i]; break; } } if (string.IsNullOrEmpty(text)) { bloodPulseStatus = "missing assets/Whoosh_Effect.wav"; return; } if (!TryReadWaveFile(text, out var samples, out var channels, out var sampleRate, out var status)) { bloodPulseStatus = "could not decode WAV: " + status; return; } Type type = FindLoadedType("UnityEngine.AudioClip"); Type type2 = FindLoadedType("UnityEngine.AudioSource"); if (type == null || type2 == null) { bloodPulseStatus = "Unity audio types were unavailable"; return; } MethodInfo method = type.GetMethod("Create", BindingFlags.Static | BindingFlags.Public, null, new Type[5] { typeof(string), typeof(int), typeof(int), typeof(int), typeof(bool) }, null); MethodInfo method2 = type.GetMethod("SetData", BindingFlags.Instance | BindingFlags.Public, null, new Type[2] { typeof(float[]), typeof(int) }, null); if (method == null || method2 == null) { blood