Decompiled source of LKKBalanceTweaks v1.0.9

BalanceTweaks.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BalanceTweaksPlugin.Effects;
using BalanceTweaksPlugin.Patches;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("LKKBalanceTweaks")]
[assembly: AssemblyDescription("A plugin that only nerfs player, only downgrade features configurable")]
[assembly: AssemblyFileVersion("1.0.9.0")]
[assembly: AssemblyInformationalVersion("1.0.9")]
[assembly: AssemblyProduct("LKKBalanceTweaks")]
[assembly: AssemblyTitle("LKKBalanceTweaks")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyVersion("1.0.9.0")]
namespace BalanceTweaksPlugin
{
	[BepInPlugin("LKKBalanceTweaks", "LKKBalanceTweaks", "1.0.9")]
	public class BalanceTweaksPlugin : BaseUnityPlugin
	{
		public static ConfigEntry<bool> CreateNetworkPrefab;

		public static ConfigEntry<bool> ShotgunConductive;

		public static ConfigEntry<bool> ShotgunEnemyDamage;

		public static ConfigEntry<bool> BeltBagShotgunAmmo;

		public static ConfigEntry<bool> ShotgunWeight;

		public static ConfigEntry<bool> ShovelWeight;

		public static ConfigEntry<bool> KnifeWeight;

		public static ConfigEntry<bool> EnableInteractDiscardBlock;

		public static ConfigEntry<bool> EnableShovelNarrowHitbox;

		public static ConfigEntry<bool> EnableShovelTriggerHit;

		public static ConfigEntry<bool> EnableShovelLinecastBlock;

		public static ConfigEntry<bool> EnableKnifeTriggerHit;

		public static ConfigEntry<bool> EnableKnifeLinecastBlock;

		public static ConfigEntry<bool> EnableJesterOwnershipCorrection;

		public static ConfigEntry<bool> EnableJesterSpeed;

		public static ConfigEntry<bool> EnableStressMechanism;

		public static ConfigEntry<bool> EnableStressHealthDrain;

		public const string PLUGIN_GUID = "LKKBalanceTweaks";

		public const string PLUGIN_NAME = "LKKBalanceTweaks";

		public const string PLUGIN_VERSION = "1.0.9";

		public const string PLUGIN_VERSION_FULL = "1.0.9.0";

		private readonly Harmony harmony = new Harmony("LKKBalanceTweaks");

		public static ManualLogSource logger;

		public static BalanceTweaksPlugin Instance;

		private void Awake()
		{
			Instance = this;
			logger = ((BaseUnityPlugin)this).Logger;
			CreateNetworkPrefab = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "CreateNetworkPrefab", false, "Define whether to create a network prefab");
			ShotgunConductive = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShotgunConductive", true, "Define whether the shotgun is conductive");
			ShotgunEnemyDamage = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShotgunEnemyDamage", true, "Define whether to nerf shotgun damage");
			BeltBagShotgunAmmo = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "BeltBagShotgunAmmo", true, "Define whether the belt bag can't store shotgun ammo");
			ShotgunWeight = ((BaseUnityPlugin)this).Config.Bind<bool>("Balance", "ShotgunWeight", true, "Define whether to modify shotgun weight");
			ShovelWeight = ((BaseUnityPlugin)this).Config.Bind<bool>("Balance", "ShovelWeight", true, "Define whether to modify shovel weight");
			KnifeWeight = ((BaseUnityPlugin)this).Config.Bind<bool>("Balance", "KnifeWeight", true, "Define whether to modify knife weight");
			EnableInteractDiscardBlock = ((BaseUnityPlugin)this).Config.Bind<bool>("Balance", "EnableInteractDiscardBlock", false, "Define whether to block interacting and discarding during shovel reel-up or knife cooldown");
			EnableShovelNarrowHitbox = ((BaseUnityPlugin)this).Config.Bind<bool>("HitDetection", "EnableShovelNarrowHitbox", true, "Define whether to narrow the shovel hit SphereCast radius");
			EnableShovelTriggerHit = ((BaseUnityPlugin)this).Config.Bind<bool>("HitDetection", "EnableShovelTriggerHit", true, "Define whether to allow shovel to hit through trigger colliders");
			EnableShovelLinecastBlock = ((BaseUnityPlugin)this).Config.Bind<bool>("HitDetection", "EnableShovelLinecastBlock", true, "Define whether to change shovel linecast queryTriggerInteraction");
			EnableKnifeTriggerHit = ((BaseUnityPlugin)this).Config.Bind<bool>("HitDetection", "EnableKnifeTriggerHit", true, "Define whether to allow knife to hit through trigger colliders");
			EnableKnifeLinecastBlock = ((BaseUnityPlugin)this).Config.Bind<bool>("HitDetection", "EnableKnifeLinecastBlock", true, "Define whether to change knife linecast queryTriggerInteraction");
			EnableJesterOwnershipCorrection = ((BaseUnityPlugin)this).Config.Bind<bool>("Jester", "EnableJesterOwnershipCorrection", true, "Define whether to periodically correct Jester ownership");
			EnableJesterSpeed = ((BaseUnityPlugin)this).Config.Bind<bool>("Jester", "EnableJesterSpeed", true, "Define whether to compute the chase speed on non-owner clients, actually a good nerf");
			EnableStressMechanism = ((BaseUnityPlugin)this).Config.Bind<bool>("Stress", "EnableStressMechanism", true, "Define whether to enable stress mechanism");
			EnableStressHealthDrain = ((BaseUnityPlugin)this).Config.Bind<bool>("Stress", "EnableStressHealthDrain", true, "Define whether to enable stress health drain");
			harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"LKKBalanceTweaks is loaded!");
			((Component)this).gameObject.AddComponent<AudioManager>();
			((Component)this).gameObject.AddComponent<StressVignetteEffect>();
			((Component)this).gameObject.AddComponent<DesaturateEffect>();
			((Component)this).gameObject.AddComponent<TinnitusEffect>();
		}
	}
}
namespace BalanceTweaksPlugin.Patches
{
	[HarmonyPatch(typeof(BeltBagItem), "TryAddObjectToBagServerRpc")]
	internal static class BeltBagShotgunAmmoPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(BeltBagItem __instance, NetworkObjectReference netObjectRef, int playerWhoAdded)
		{
			if (!((NetworkBehaviour)__instance).IsHost)
			{
				return true;
			}
			if (!BalanceTweaksPlugin.BeltBagShotgunAmmo.Value)
			{
				return true;
			}
			NetworkObject val = default(NetworkObject);
			if (((NetworkObjectReference)(ref netObjectRef)).TryGet(ref val, (NetworkManager)null) && ((Component)val).GetComponent<GrabbableObject>() is GunAmmo)
			{
				__instance.CancelAddObjectToBagClientRpc(playerWhoAdded);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(FlashlightItem), "DiscardItem")]
	internal static class FlashlightDiscardItemPatch
	{
		[HarmonyPrefix]
		private static void Prefix(FlashlightItem __instance)
		{
			if (((GrabbableObject)__instance).isBeingUsed && ((GrabbableObject)__instance).insertedBattery != null && !((GrabbableObject)__instance).insertedBattery.empty && (int)(((GrabbableObject)__instance).insertedBattery.charge * 100f) == 0)
			{
				((GrabbableObject)__instance).UseUpBatteries();
			}
		}
	}
	internal static class InteractDiscardCooldownPatch
	{
		private const float KnifeCooldownTime = 0.43f;

		private static readonly FieldInfo knifeCooldownField = AccessTools.Field(typeof(KnifeItem), "timeAtLastDamageDealt");

		internal static bool IsInCooldown(PlayerControllerB player)
		{
			GrabbableObject currentlyHeldObjectServer = player.currentlyHeldObjectServer;
			if ((Object)(object)currentlyHeldObjectServer == (Object)null)
			{
				return false;
			}
			Shovel val = (Shovel)(object)((currentlyHeldObjectServer is Shovel) ? currentlyHeldObjectServer : null);
			if ((Object)(object)val != (Object)null && val.reelingUp)
			{
				return true;
			}
			KnifeItem val2 = (KnifeItem)(object)((currentlyHeldObjectServer is KnifeItem) ? currentlyHeldObjectServer : null);
			if ((Object)(object)val2 != (Object)null && Time.realtimeSinceStartup - (float)knifeCooldownField.GetValue(val2) < 0.43f)
			{
				return true;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "Interact_performed")]
	internal static class BlockInteractPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(PlayerControllerB __instance)
		{
			if (!BalanceTweaksPlugin.EnableInteractDiscardBlock.Value)
			{
				return true;
			}
			return !InteractDiscardCooldownPatch.IsInCooldown(__instance);
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "Discard_performed")]
	internal static class BlockDiscardPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(PlayerControllerB __instance)
		{
			if (!BalanceTweaksPlugin.EnableInteractDiscardBlock.Value)
			{
				return true;
			}
			return !InteractDiscardCooldownPatch.IsInCooldown(__instance);
		}
	}
	[HarmonyPatch(typeof(JesterAI), "OnCollideWithPlayer")]
	internal static class JesterCollisionTransferPatch
	{
		private static readonly FieldRef<JesterAI, bool> inKillAnimation = AccessTools.FieldRefAccess<JesterAI, bool>("inKillAnimation");

		private static readonly MethodInfo isSeparatedByMineshaftElevator = AccessTools.Method(typeof(EnemyAI), "IsSeparatedByMineshaftElevator", (Type[])null, (Type[])null);

		[HarmonyPostfix]
		private static void Postfix(JesterAI __instance, Collider other)
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			if (((EnemyAI)__instance).currentBehaviourStateIndex == 2 && ((NetworkBehaviour)__instance).IsOwner && !((EnemyAI)__instance).isEnemyDead && ((EnemyAI)__instance).ventAnimationFinished)
			{
				PlayerControllerB val = ((other != null) ? ((Component)other).GetComponent<PlayerControllerB>() : null);
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)GameNetworkManager.Instance.localPlayerController) && !inKillAnimation.Invoke(__instance) && !(((EnemyAI)__instance).stunNormalizedTimer >= 0f) && ((EnemyAI)__instance).PlayerIsTargetable(val, false, false, true) && !(bool)isSeparatedByMineshaftElevator.Invoke(__instance, new object[1] { ((Component)val).transform.position }))
				{
					((EnemyAI)__instance).ChangeOwnershipOfEnemy(val.actualClientId);
				}
			}
		}
	}
	[HarmonyPatch(typeof(RoundManager), "Update")]
	internal static class JesterOwnershipCorrectionPatch
	{
		private static float _timer;

		[HarmonyPostfix]
		private static void Postfix()
		{
			if (!BalanceTweaksPlugin.EnableJesterOwnershipCorrection.Value)
			{
				return;
			}
			_timer += Time.deltaTime;
			if (_timer < 0.8f)
			{
				return;
			}
			_timer = 0f;
			List<EnemyAI> spawnedEnemies = RoundManager.Instance.SpawnedEnemies;
			if (spawnedEnemies == null)
			{
				return;
			}
			for (int i = 0; i < spawnedEnemies.Count; i++)
			{
				EnemyAI val = spawnedEnemies[i];
				if ((Object)(object)val == (Object)null || val.isEnemyDead)
				{
					continue;
				}
				JesterAI val2 = (JesterAI)(object)((val is JesterAI) ? val : null);
				if (val2 != null && ((EnemyAI)val2).currentBehaviourStateIndex == 2 && ((NetworkBehaviour)val2).IsOwner)
				{
					PlayerControllerB targetPlayer = ((EnemyAI)val2).targetPlayer;
					if (!((Object)(object)targetPlayer == (Object)null) && ((EnemyAI)val2).PlayerIsTargetable(targetPlayer, false, false, true) && !((Object)(object)targetPlayer == (Object)(object)GameNetworkManager.Instance.localPlayerController))
					{
						((EnemyAI)val2).ChangeOwnershipOfEnemy(targetPlayer.actualClientId);
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(JesterAI), "Update")]
	internal static class JesterSpeedPatch
	{
		private static readonly FieldRef<JesterAI, bool> inKillAnimation = AccessTools.FieldRefAccess<JesterAI, bool>("inKillAnimation");

		[HarmonyPostfix]
		private static void Postfix(JesterAI __instance)
		{
			if (BalanceTweaksPlugin.EnableJesterSpeed.Value && !((EnemyAI)__instance).isEnemyDead && ((EnemyAI)__instance).currentBehaviourStateIndex == 2 && !((NetworkBehaviour)__instance).IsOwner)
			{
				if (inKillAnimation.Invoke(__instance) || ((EnemyAI)__instance).stunNormalizedTimer > 0f)
				{
					((EnemyAI)__instance).agent.speed = 0f;
				}
				else
				{
					((EnemyAI)__instance).agent.speed = Mathf.Clamp(((EnemyAI)__instance).agent.speed + Time.deltaTime * 1.45f, 0f, 18f);
				}
			}
		}
	}
	[HarmonyPatch(typeof(EnemyAI), "SwitchToBehaviourState")]
	internal static class JesterStatePatch
	{
		[HarmonyPostfix]
		private static void Postfix(EnemyAI __instance, int stateIndex)
		{
			if (stateIndex == 2 && __instance is JesterAI && ((NetworkBehaviour)__instance).IsServer && ((NetworkBehaviour)__instance).IsOwner && !((Object)(object)__instance.targetPlayer == (Object)null) && !((Object)(object)__instance.targetPlayer == (Object)(object)GameNetworkManager.Instance.localPlayerController))
			{
				__instance.ChangeOwnershipOfEnemy(__instance.targetPlayer.actualClientId);
			}
		}
	}
	[HarmonyPatch(typeof(KnifeItem), "HitKnife")]
	internal static class KnifeAttackPatch
	{
		private const int QueryTriggerIgnore = 1;

		private const int QueryTriggerUseGlobal = 0;

		private const sbyte QueryTriggerIgnore_SByte = 1;

		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			for (int i = 0; i < list.Count; i++)
			{
				CodeInstruction val = list[i];
				if (BalanceTweaksPlugin.EnableKnifeLinecastBlock.Value && i + 1 < list.Count && list[i + 1].opcode == OpCodes.Call && list[i + 1].operand is MethodInfo { Name: "Linecast", IsStatic: not false })
				{
					if (val.opcode == OpCodes.Ldc_I4_1)
					{
						val.opcode = OpCodes.Ldc_I4_0;
						val.operand = null;
					}
					else if (val.opcode == OpCodes.Ldc_I4_S && val.operand is sbyte b && b == 1)
					{
						val.operand = (sbyte)0;
					}
					else if (val.opcode == OpCodes.Ldc_I4 && val.operand is int num && num == 1)
					{
						val.operand = 0;
					}
				}
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(KnifeItem), "HitKnife")]
	internal static class KnifeTriggerPatch
	{
		private static readonly MethodInfo IsTriggerGetter = AccessTools.PropertyGetter(typeof(Collider), "isTrigger");

		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			if (!BalanceTweaksPlugin.EnableKnifeTriggerHit.Value)
			{
				return instructions;
			}
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			for (int i = 0; i < list.Count; i++)
			{
				if (!(list[i].opcode == OpCodes.Callvirt) || !(list[i].operand is MethodInfo methodInfo) || !(methodInfo == IsTriggerGetter))
				{
					continue;
				}
				list[i].opcode = OpCodes.Pop;
				list[i].operand = null;
				for (int j = i + 1; j < list.Count; j++)
				{
					if (list[j].opcode == OpCodes.Brtrue || list[j].opcode == OpCodes.Brtrue_S)
					{
						list[j].opcode = OpCodes.Nop;
						list[j].operand = null;
						break;
					}
				}
				break;
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "Start")]
	internal static class KnifeWeightPatch
	{
		[HarmonyPostfix]
		private static void ModifyKnifeWeight()
		{
			if (!BalanceTweaksPlugin.KnifeWeight.Value)
			{
				return;
			}
			foreach (Item items in StartOfRound.Instance.allItemsList.itemsList)
			{
				if (items.itemName == "Kitchen knife")
				{
					items.weight = 1.05f;
					break;
				}
			}
		}
	}
	[HarmonyPatch(typeof(NetworkManager), "SetSingleton")]
	internal static class NetworkPrefabPatch
	{
		private static void Postfix()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if (!BalanceTweaksPlugin.CreateNetworkPrefab.Value || (Object)(object)NetworkManager.Singleton == (Object)null || NetworkManager.Singleton.PrefabHandler == null)
			{
				return;
			}
			GameObject val = new GameObject("LKKBalanceTweaks Prefab");
			((Object)val).hideFlags = (HideFlags)(((Object)val).hideFlags | 0x3D);
			Object.DontDestroyOnLoad((Object)(object)val);
			NetworkObject obj = val.AddComponent<NetworkObject>();
			try
			{
				FieldInfo field = typeof(NetworkObject).GetField("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.NonPublic);
				if (field != null)
				{
					uint hashCode = (uint)"LKKBalanceTweaks".GetHashCode();
					field.SetValue(obj, hashCode);
				}
			}
			catch
			{
			}
			NetworkManager.Singleton.PrefabHandler.AddNetworkPrefab(val);
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "Start")]
	internal static class ShotgunConductivePatch
	{
		[HarmonyPostfix]
		private static void MakeShotgunConductive()
		{
			if (!BalanceTweaksPlugin.ShotgunConductive.Value || !((NetworkBehaviour)StartOfRound.Instance).IsHost)
			{
				return;
			}
			foreach (Item items in StartOfRound.Instance.allItemsList.itemsList)
			{
				if (items.itemName == "Shotgun")
				{
					items.isConductiveMetal = true;
					break;
				}
			}
		}
	}
	[HarmonyPatch(typeof(ShotgunItem), "ShootGun")]
	internal static class ShotgunEnemyDamagePatch
	{
		private const float OriginalRangeThreshold = 3.7f;

		private const int OriginalDamageClose = 5;

		private const int OriginalDamageMedium = 3;

		private const int OriginalDamageFar = 2;

		private const int DamageClose = 4;

		private const int DamageMedium = 3;

		private const int DamageFar = 2;

		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			int remainingMatches = 0;
			foreach (CodeInstruction instruction in instructions)
			{
				if (instruction.opcode == OpCodes.Ldc_R4 && Mathf.Approximately((float)instruction.operand, 3.7f))
				{
					remainingMatches = 3;
				}
				if (remainingMatches > 0)
				{
					if (instruction.opcode == OpCodes.Ldc_I4_5)
					{
						instruction.opcode = OpCodes.Ldc_I4;
						instruction.operand = 4;
						remainingMatches--;
					}
					else if (instruction.opcode == OpCodes.Ldc_I4_3)
					{
						instruction.opcode = OpCodes.Ldc_I4;
						instruction.operand = 3;
						remainingMatches--;
					}
					else if (instruction.opcode == OpCodes.Ldc_I4_2)
					{
						instruction.opcode = OpCodes.Ldc_I4;
						instruction.operand = 2;
						remainingMatches--;
					}
					else if (instruction.opcode == OpCodes.Ldc_I4 && instruction.operand is int num && (num == 5 || num == 3 || num == 2))
					{
						instruction.operand = num switch
						{
							3 => 3, 
							5 => 4, 
							_ => 2, 
						};
						remainingMatches--;
					}
				}
				yield return instruction;
			}
		}
	}
	[HarmonyPatch(typeof(EnemyAI), "HitEnemyServerRpc")]
	internal static class ShotgunEnemyDamageSyncPatch
	{
		private static readonly int[] OriginalDamage = new int[3] { 5, 3, 2 };

		private static readonly int[] ModdedDamage = new int[3] { 4, 3, 2 };

		[HarmonyPrefix]
		private static void SyncShotgunDamage(ref int force, int playerWhoHit)
		{
			if (!((NetworkBehaviour)StartOfRound.Instance).IsHost || playerWhoHit < 0 || playerWhoHit >= StartOfRound.Instance.allPlayerScripts.Length)
			{
				return;
			}
			PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[playerWhoHit];
			if ((Object)(object)val == (Object)null || !(val.currentlyHeldObjectServer is ShotgunItem))
			{
				return;
			}
			int[] array = (BalanceTweaksPlugin.ShotgunEnemyDamage.Value ? OriginalDamage : ModdedDamage);
			int[] array2 = (BalanceTweaksPlugin.ShotgunEnemyDamage.Value ? ModdedDamage : OriginalDamage);
			for (int i = 0; i < array.Length; i++)
			{
				if (force == array[i])
				{
					force = array2[i];
					break;
				}
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "Start")]
	internal static class ShotgunWeightPatch
	{
		[HarmonyPostfix]
		private static void ModifyShotgunWeight()
		{
			if (!BalanceTweaksPlugin.ShotgunWeight.Value)
			{
				return;
			}
			foreach (Item items in StartOfRound.Instance.allItemsList.itemsList)
			{
				if (items.itemName == "Shotgun")
				{
					items.weight = 1.2f;
					break;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Shovel), "HitShovel")]
	internal static class ShovelAttackPatch
	{
		private const float OriginalSphereCastRadius = 0.8f;

		private const float SphereCastRadius = 0.75f;

		private const float OriginalSphereCastDistance = 1.5f;

		private const float SphereCastDistance = 1.5f;

		private const float FloatComparisonEpsilon = 0.0001f;

		private const int QueryTriggerIgnore = 1;

		private const int QueryTriggerUseGlobal = 0;

		private const sbyte QueryTriggerIgnore_SByte = 1;

		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			for (int i = 0; i < list.Count; i++)
			{
				CodeInstruction val = list[i];
				if (BalanceTweaksPlugin.EnableShovelNarrowHitbox.Value && val.opcode == OpCodes.Ldc_R4 && val.operand is float num)
				{
					if (Math.Abs(num - 0.8f) < 0.0001f)
					{
						val.operand = 0.75f;
					}
					else if (Math.Abs(num - 1.5f) < 0.0001f)
					{
						val.operand = 1.5f;
					}
				}
				if (BalanceTweaksPlugin.EnableShovelLinecastBlock.Value && i + 1 < list.Count && list[i + 1].opcode == OpCodes.Call && list[i + 1].operand is MethodInfo { Name: "Linecast", IsStatic: not false })
				{
					if (val.opcode == OpCodes.Ldc_I4_1)
					{
						val.opcode = OpCodes.Ldc_I4_0;
						val.operand = null;
					}
					else if (val.opcode == OpCodes.Ldc_I4_S && val.operand is sbyte b && b == 1)
					{
						val.operand = (sbyte)0;
					}
					else if (val.opcode == OpCodes.Ldc_I4 && val.operand is int num2 && num2 == 1)
					{
						val.operand = 0;
					}
				}
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(Shovel), "HitShovel")]
	internal static class ShovelTriggerPatch
	{
		private static readonly MethodInfo IsTriggerGetter = AccessTools.PropertyGetter(typeof(Collider), "isTrigger");

		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			if (!BalanceTweaksPlugin.EnableShovelTriggerHit.Value)
			{
				return instructions;
			}
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			for (int i = 0; i < list.Count; i++)
			{
				if (!(list[i].opcode == OpCodes.Callvirt) || !(list[i].operand is MethodInfo methodInfo) || !(methodInfo == IsTriggerGetter))
				{
					continue;
				}
				list[i].opcode = OpCodes.Pop;
				list[i].operand = null;
				for (int j = i + 1; j < list.Count; j++)
				{
					if (list[j].opcode == OpCodes.Brtrue || list[j].opcode == OpCodes.Brtrue_S)
					{
						list[j].opcode = OpCodes.Nop;
						list[j].operand = null;
						break;
					}
				}
				break;
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "Start")]
	internal static class ShovelWeightPatch
	{
		[HarmonyPostfix]
		private static void ModifyShovelWeight()
		{
			if (!BalanceTweaksPlugin.ShovelWeight.Value)
			{
				return;
			}
			foreach (Item items in StartOfRound.Instance.allItemsList.itemsList)
			{
				if (items.itemName == "Shovel")
				{
					items.weight = 1.18f;
					break;
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "ScrollMouse_performed")]
	internal static class BlockScrollSwitchPatch
	{
		private const float KnifeCooldownTime = 0.43f;

		private static readonly FieldInfo knifeCooldownField = AccessTools.Field(typeof(KnifeItem), "timeAtLastDamageDealt");

		[HarmonyPrefix]
		private static bool Prefix(PlayerControllerB __instance)
		{
			GrabbableObject currentlyHeldObjectServer = __instance.currentlyHeldObjectServer;
			Shovel val = (Shovel)(object)((currentlyHeldObjectServer is Shovel) ? currentlyHeldObjectServer : null);
			if ((Object)(object)val != (Object)null && val.reelingUp)
			{
				return false;
			}
			GrabbableObject currentlyHeldObjectServer2 = __instance.currentlyHeldObjectServer;
			KnifeItem val2 = (KnifeItem)(object)((currentlyHeldObjectServer2 is KnifeItem) ? currentlyHeldObjectServer2 : null);
			if ((Object)(object)val2 != (Object)null && Time.realtimeSinceStartup - (float)knifeCooldownField.GetValue(val2) < 0.43f)
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "UseUtilitySlot_performed")]
	internal static class BlockUtilitySlotSwitchPatch
	{
		private const float KnifeCooldownTime = 0.43f;

		private static readonly FieldInfo knifeCooldownField = AccessTools.Field(typeof(KnifeItem), "timeAtLastDamageDealt");

		[HarmonyPrefix]
		private static bool Prefix(PlayerControllerB __instance)
		{
			GrabbableObject currentlyHeldObjectServer = __instance.currentlyHeldObjectServer;
			Shovel val = (Shovel)(object)((currentlyHeldObjectServer is Shovel) ? currentlyHeldObjectServer : null);
			if ((Object)(object)val != (Object)null && val.reelingUp)
			{
				return false;
			}
			GrabbableObject currentlyHeldObjectServer2 = __instance.currentlyHeldObjectServer;
			KnifeItem val2 = (KnifeItem)(object)((currentlyHeldObjectServer2 is KnifeItem) ? currentlyHeldObjectServer2 : null);
			if ((Object)(object)val2 != (Object)null && Time.realtimeSinceStartup - (float)knifeCooldownField.GetValue(val2) < 0.43f)
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "Update")]
	internal static class StressHealthDrainPatch
	{
		private sealed class DrainState
		{
			public float timer;
		}

		private const float DrainInterval = 0.5f;

		private const int DrainAmount = 5;

		private static readonly ConditionalWeakTable<PlayerControllerB, DrainState> drainStates = new ConditionalWeakTable<PlayerControllerB, DrainState>();

		[HarmonyPostfix]
		private static void Postfix(PlayerControllerB __instance)
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			if (!BalanceTweaksPlugin.EnableStressMechanism.Value || !BalanceTweaksPlugin.EnableStressHealthDrain.Value || (Object)(object)__instance != (Object)(object)GameNetworkManager.Instance.localPlayerController)
			{
				return;
			}
			DrainState orCreateValue = drainStates.GetOrCreateValue(__instance);
			if (StressMechanismPatch.GetEffectiveSprintMeter(__instance) > 0f || __instance.isPlayerDead)
			{
				orCreateValue.timer = 0f;
				return;
			}
			orCreateValue.timer += Time.deltaTime;
			if (!(orCreateValue.timer < 0.5f))
			{
				orCreateValue.timer = 0f;
				__instance.DamagePlayer(5, true, true, (CauseOfDeath)5, 0, false, default(Vector3));
			}
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "Update")]
	internal static class StressMechanismPatch
	{
		[HarmonyPatch(typeof(PlayerControllerB), "DamagePlayer")]
		internal static class DamageTakenStressPatch
		{
			[HarmonyPostfix]
			private static void Postfix(PlayerControllerB __instance, int damageNumber)
			{
				if (!((Object)(object)__instance != (Object)(object)GameNetworkManager.Instance.localPlayerController))
				{
					pendingDamageTaken += damageNumber;
				}
			}
		}

		[HarmonyPatch(typeof(LungProp), "EquipItem")]
		internal static class ApparatusPulledPatch
		{
			private const float PullStressGain = 0.04f;

			[HarmonyPrefix]
			private static void Prefix(LungProp __instance)
			{
				if (BalanceTweaksPlugin.EnableStressMechanism.Value && __instance.isLungDocked)
				{
					PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController;
					if (!((Object)(object)localPlayerController == (Object)null) && !localPlayerController.isPlayerDead)
					{
						stressTimer = Mathf.Min(1f, stressTimer + 0.04f);
					}
				}
			}
		}

		private static readonly FieldRef<PlayerControllerB, bool> isWalking = AccessTools.FieldRefAccess<PlayerControllerB, bool>("isWalking");

		private const float HealthFactorStartHp = 100f;

		private const float HealthFactorEndHp = 20f;

		private const float HealthFactorMultiplier = 0.2f;

		private const float FearFactorMultiplier = 0.2f;

		private const float SoloShipRate = 0.000462f;

		private const float SoloOutsideRate = 0.000694f;

		private const float SoloFactoryRate = 0.000925f;

		private const float MultiShipRate = 0.000694f;

		private const float MultiOutsideRate = 0.001041f;

		private const float MultiFactoryRate = 0.001388f;

		private const float NearOthersRadius = 17f;

		private const float CompanionshipMultiplier = 0.5f;

		private const float PlayerFactorMultiplier = 1.15f;

		private static readonly HashSet<string> NoStressLevelSceneNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "CompanyBuilding" };

		internal static float stressTimer;

		internal static float pendingDamageTaken;

		internal static int otherTotal;

		internal static int otherAlive;

		internal static float alivePercent;

		internal static float currentLocationRate;

		[HarmonyPostfix]
		private static void Postfix(PlayerControllerB __instance)
		{
			UpdateStress(__instance);
			__instance.sprintMeter = GetEffectiveSprintMeter(__instance);
		}

		internal static void UpdateStress(PlayerControllerB player)
		{
			if (BalanceTweaksPlugin.EnableStressMechanism.Value && !((Object)(object)player != (Object)(object)GameNetworkManager.Instance.localPlayerController))
			{
				UpdateStressTimer(player);
			}
		}

		internal static float GetEffectiveSprintMeter(PlayerControllerB player)
		{
			if (!BalanceTweaksPlugin.EnableStressMechanism.Value)
			{
				return player.sprintMeter;
			}
			if ((Object)(object)player != (Object)(object)GameNetworkManager.Instance.localPlayerController)
			{
				return player.sprintMeter;
			}
			if (!player.isInsideFactory)
			{
				return player.sprintMeter;
			}
			if (player.isSprinting)
			{
				return player.sprintMeter;
			}
			if (player.isCrouching)
			{
				return player.sprintMeter;
			}
			if (player.isMovementHindered > 0)
			{
				return player.sprintMeter;
			}
			if (!isWalking.Invoke(player))
			{
				return player.sprintMeter;
			}
			float num = 1f;
			if (player.drunkness > 0.02f)
			{
				num *= Mathf.Abs(StartOfRound.Instance.drunknessSpeedEffect.Evaluate(player.drunkness) - 1.25f);
			}
			float deltaTime = Time.deltaTime;
			float num2 = stressTimer * 0.3f;
			float num3 = deltaTime / (player.sprintTime + 9f) * num;
			float num4 = deltaTime / player.sprintTime * player.carryWeight * num * num2;
			float num5 = Mathf.Clamp01(stressTimer / 0.5f);
			float num6 = Mathf.InverseLerp(0.5f, 1f, stressTimer);
			float num7 = num4 * num6;
			return Mathf.Clamp(player.sprintMeter - num3 * num5 - num7, 0f, 1f);
		}

		private static bool IsNoStressLevel()
		{
			if ((Object)(object)StartOfRound.Instance != (Object)null && (Object)(object)StartOfRound.Instance.currentLevel != (Object)null)
			{
				return NoStressLevelSceneNames.Contains(StartOfRound.Instance.currentLevel.sceneName);
			}
			return false;
		}

		private static float GetLocationRate(PlayerControllerB player)
		{
			bool flag = otherTotal == 0;
			if (player.isInsideFactory)
			{
				if (!flag)
				{
					return 0.001388f;
				}
				return 0.000925f;
			}
			if (player.isInHangarShipRoom)
			{
				if (!flag)
				{
					return 0.000694f;
				}
				return 0.000462f;
			}
			if (!flag)
			{
				return 0.001041f;
			}
			return 0.000694f;
		}

		internal static float GetHealthFactor(PlayerControllerB player)
		{
			return Mathf.Lerp(0f, 0.2f, Mathf.InverseLerp(100f, 20f, (float)player.health));
		}

		private static void UpdateStressTimer(PlayerControllerB player)
		{
			if (player.isPlayerDead)
			{
				return;
			}
			otherTotal = StartOfRound.Instance.connectedPlayersAmount;
			otherAlive = StartOfRound.Instance.livingPlayers - ((!player.isPlayerDead) ? 1 : 0);
			alivePercent = ((otherTotal > 0) ? Mathf.Clamp01((float)otherAlive / (float)otherTotal) : 0f);
			bool flag = otherTotal == 0;
			float num = ((!flag) ? Mathf.Lerp(0.00075f, 0.000375f, alivePercent) : 0.0005f);
			if (StartOfRound.Instance.inShipPhase)
			{
				stressTimer = 0f;
				pendingDamageTaken = 0f;
			}
			else if (!IsNoStressLevel())
			{
				float healthFactor = GetHealthFactor(player);
				float num2 = Mathf.Lerp(0f, 0.2f, Mathf.Clamp01(StartOfRound.Instance.fearLevel));
				float num3 = (flag ? 1f : Mathf.Lerp(1.15f, 1f, alivePercent));
				float num4 = (player.NearOtherPlayers(17f) ? 0.5f : 1f);
				float num5 = (currentLocationRate = GetLocationRate(player) * (1f + healthFactor + num2) * num3 * num4);
				stressTimer += Time.deltaTime * num5;
				if (pendingDamageTaken > 0f)
				{
					stressTimer += pendingDamageTaken * num * (1f + healthFactor);
					pendingDamageTaken = 0f;
				}
				stressTimer = Mathf.Clamp(stressTimer, 0f, 1f);
			}
		}
	}
}
namespace BalanceTweaksPlugin.Effects
{
	internal class AudioManager : MonoBehaviour
	{
		private const string BasicFolder = "Basic";

		private const string HallucinationFolder = "Hallucination";

		private const string HallucinationPrefix = "Hallucination";

		private const string BlackoutSoundName = "Blackout";

		private const string DesaturateSoundName = "Desaturate";

		private const string TinnitusSoundName = "Tinnitus";

		private const float SoundVolume = 1f;

		private static readonly string[] AudioExtensions = new string[3] { ".wav", ".ogg", ".mp3" };

		private AudioSource blackoutSource;

		private AudioSource desaturateSource;

		private AudioSource tinnitusSource;

		private AudioSource hallucinationSource;

		private float desaturateTargetVolume = 1f;

		private AudioClip blackoutClip;

		private AudioClip desaturateClip;

		private AudioClip tinnitusClip;

		private readonly List<AudioClip> hallucinationClips = new List<AudioClip>();

		private void Awake()
		{
			blackoutSource = CreateSource();
			desaturateSource = CreateSource();
			tinnitusSource = CreateSource();
			hallucinationSource = CreateSource();
			((MonoBehaviour)this).StartCoroutine(LoadClip("Blackout", "Basic", delegate(AudioClip clip)
			{
				blackoutClip = clip;
			}));
			((MonoBehaviour)this).StartCoroutine(LoadClip("Desaturate", "Basic", delegate(AudioClip clip)
			{
				desaturateClip = clip;
			}));
			((MonoBehaviour)this).StartCoroutine(LoadClip("Tinnitus", "Basic", delegate(AudioClip clip)
			{
				tinnitusClip = clip;
			}));
			((MonoBehaviour)this).StartCoroutine(LoadHallucinationClips());
		}

		private void Update()
		{
			if (!((Object)(object)desaturateSource == (Object)null))
			{
				desaturateSource.volume = Mathf.Lerp(desaturateSource.volume, desaturateTargetVolume, 5f * Time.deltaTime);
			}
		}

		private AudioSource CreateSource()
		{
			AudioSource obj = ((Component)this).gameObject.AddComponent<AudioSource>();
			obj.playOnAwake = false;
			obj.loop = false;
			obj.spatialBlend = 0f;
			obj.volume = 1f;
			return obj;
		}

		private void PlayOneShot(AudioSource source, AudioClip clip)
		{
			if (!((Object)(object)source == (Object)null) && !((Object)(object)clip == (Object)null))
			{
				source.PlayOneShot(clip);
			}
		}

		public void PlayBlackoutSound()
		{
			PlayOneShot(blackoutSource, blackoutClip);
		}

		public void PlayDesaturateSound()
		{
			PlayOneShot(desaturateSource, desaturateClip);
		}

		public void PlayTinnitusSound()
		{
			PlayOneShot(tinnitusSource, tinnitusClip);
		}

		public void PlayHallucinationSound()
		{
			if (hallucinationClips.Count != 0)
			{
				PlayOneShot(hallucinationSource, hallucinationClips[Random.Range(0, hallucinationClips.Count)]);
			}
		}

		private void StopOneShot(AudioSource source)
		{
			if (!((Object)(object)source == (Object)null))
			{
				source.Stop();
			}
		}

		public void StopBlackoutSound()
		{
			StopOneShot(blackoutSource);
		}

		public void StopDesaturateSound()
		{
			StopOneShot(desaturateSource);
		}

		public void StopTinnitusSound()
		{
			StopOneShot(tinnitusSource);
		}

		public void StopHallucinationSound()
		{
			StopOneShot(hallucinationSource);
		}

		public void SetDesaturateSoundMuted(bool muted)
		{
			desaturateTargetVolume = (muted ? 0f : 1f);
		}

		private IEnumerator LoadClip(string baseName, string subDir, Action<AudioClip> onLoaded)
		{
			if (string.IsNullOrWhiteSpace(baseName))
			{
				yield break;
			}
			string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "assets", subDir);
			string text2 = null;
			AudioType audioType = (AudioType)20;
			string[] audioExtensions = AudioExtensions;
			foreach (string text3 in audioExtensions)
			{
				string text4 = Path.Combine(text, baseName + text3);
				if (File.Exists(text4))
				{
					text2 = text4;
					audioType = GetAudioType(text3);
					break;
				}
			}
			if (text2 == null)
			{
				BalanceTweaksPlugin.logger.LogWarning((object)("Stress sound '" + baseName + "' not found in '" + text + "' (tried " + string.Join(", ", AudioExtensions) + ")"));
			}
			else
			{
				yield return LoadClipAtPath(text2, audioType, onLoaded);
			}
		}

		private IEnumerator LoadHallucinationClips()
		{
			string dir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "assets", "Hallucination");
			if (!Directory.Exists(dir))
			{
				BalanceTweaksPlugin.logger.LogWarning((object)("Hallucination sound folder not found: " + dir));
				yield break;
			}
			string[] files = Directory.GetFiles(dir);
			foreach (string path in files)
			{
				if (!Path.GetFileNameWithoutExtension(path).StartsWith("Hallucination", StringComparison.OrdinalIgnoreCase))
				{
					continue;
				}
				string text = Path.GetExtension(path).ToLowerInvariant();
				if (Array.IndexOf(AudioExtensions, text) >= 0)
				{
					yield return LoadClipAtPath(path, GetAudioType(text), delegate(AudioClip clip)
					{
						hallucinationClips.Add(clip);
					});
				}
			}
			if (hallucinationClips.Count == 0)
			{
				BalanceTweaksPlugin.logger.LogWarning((object)("No hallucination sounds found in '" + dir + "' (expected files starting with 'Hallucination')"));
			}
		}

		private IEnumerator LoadClipAtPath(string path, AudioType audioType, Action<AudioClip> onLoaded)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip("file://" + path, audioType);
			try
			{
				request.SendWebRequest();
				while (!request.isDone)
				{
					yield return null;
				}
				if ((int)request.result != 1)
				{
					BalanceTweaksPlugin.logger.LogWarning((object)("Failed to load stress sound '" + path + "': " + request.error));
					yield break;
				}
				AudioClip content = DownloadHandlerAudioClip.GetContent(request);
				if ((Object)(object)content == (Object)null)
				{
					BalanceTweaksPlugin.logger.LogWarning((object)("Stress sound '" + path + "' loaded but produced no clip."));
				}
				else
				{
					onLoaded?.Invoke(content);
				}
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private static AudioType GetAudioType(string extension)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			string text = extension.ToLowerInvariant();
			if (!(text == ".ogg"))
			{
				if (text == ".mp3")
				{
					return (AudioType)13;
				}
				return (AudioType)20;
			}
			return (AudioType)14;
		}
	}
	internal class DesaturateEffect : MonoBehaviour
	{
		private const float DesaturateSaturation = -100f;

		private const float TriggerThreshold = 0.6f;

		private const float MinChancePerSecond = 0.01f;

		private const float MaxChancePerSecond = 0.2f;

		private const float CooldownAtThreshold = 90f;

		private const float CooldownAtMaxStress = 45f;

		private const float DesaturateDuration = 12f;

		private AudioManager audio;

		private Volume desaturateVolume;

		private ColorAdjustments colorAdjustments;

		private bool hallucinationActive;

		private float hallucinationTimer;

		private float cooldownRemaining;

		private void Awake()
		{
			CreateVolume();
			audio = ((Component)this).GetComponent<AudioManager>();
		}

		private void Update()
		{
			if (hallucinationActive)
			{
				if (InGameContext())
				{
					UpdateActiveHallucination();
				}
				else
				{
					EndHallucination(StressMechanismPatch.stressTimer);
				}
			}
			else if (cooldownRemaining > 0f)
			{
				cooldownRemaining -= Time.deltaTime;
			}
			else
			{
				if (!InGameContext())
				{
					return;
				}
				float stressTimer = StressMechanismPatch.stressTimer;
				if (stressTimer > 0.6f)
				{
					float num = Mathf.InverseLerp(0.6f, 1f, stressTimer);
					float num2 = Mathf.Lerp(0.01f, 0.2f, num) * Time.deltaTime;
					if (Random.value < num2)
					{
						StartHallucination();
					}
				}
			}
		}

		private void CreateVolume()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			GameObject val = new GameObject("StressDesaturateVolume");
			val.transform.SetParent(((Component)this).transform, false);
			desaturateVolume = val.AddComponent<Volume>();
			desaturateVolume.isGlobal = true;
			desaturateVolume.priority = 100f;
			desaturateVolume.weight = 0f;
			VolumeProfile val2 = ScriptableObject.CreateInstance<VolumeProfile>();
			desaturateVolume.profile = val2;
			colorAdjustments = val2.Add<ColorAdjustments>(true);
			((VolumeParameter<float>)(object)colorAdjustments.saturation).Override(0f);
			((VolumeParameter)colorAdjustments.postExposure).overrideState = false;
		}

		private bool InGameContext()
		{
			if (!BalanceTweaksPlugin.EnableStressMechanism.Value)
			{
				return false;
			}
			if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.inShipPhase)
			{
				return false;
			}
			PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
			if ((Object)(object)val != (Object)null && !val.isPlayerDead)
			{
				return val.isInsideFactory;
			}
			return false;
		}

		private void StartHallucination()
		{
			hallucinationActive = true;
			hallucinationTimer = 0f;
			audio.PlayDesaturateSound();
		}

		private void UpdateActiveHallucination()
		{
			hallucinationTimer += Time.deltaTime;
			((VolumeParameter<float>)(object)colorAdjustments.saturation).Override(-100f);
			desaturateVolume.weight = 1f;
			if (hallucinationTimer >= 12f)
			{
				EndHallucination(StressMechanismPatch.stressTimer);
			}
		}

		private void EndHallucination(float stress)
		{
			if (hallucinationActive)
			{
				hallucinationActive = false;
				((VolumeParameter<float>)(object)colorAdjustments.saturation).Override(0f);
				desaturateVolume.weight = 0f;
				audio.StopDesaturateSound();
				float num = Mathf.InverseLerp(0.6f, 1f, stress);
				cooldownRemaining = Mathf.Lerp(90f, 45f, num);
			}
		}
	}
	internal class StressVignetteEffect : MonoBehaviour
	{
		private const float VignetteIntensity = 0.85f;

		private const float VignetteSmoothness = 0.6f;

		private const float CenterExposure = -1f;

		private const float TriggerThreshold = 0.4f;

		private const float MinChancePerSecond = 0.01f;

		private const float MaxChancePerSecond = 0.225f;

		private const float CooldownAtThreshold = 80f;

		private const float CooldownAtMaxStress = 40f;

		private const float BlackoutDuration = 12f;

		private AudioManager audio;

		private Volume stressVolume;

		private Vignette vignette;

		private ColorAdjustments colorAdjustments;

		private bool blackoutActive;

		private float blackoutTimer;

		private float blackoutDuration;

		private float cooldownRemaining;

		private void Awake()
		{
			CreateVolume();
			audio = ((Component)this).GetComponent<AudioManager>();
		}

		private void Update()
		{
			if (blackoutActive)
			{
				if (InGameContext())
				{
					UpdateBlackout(StressMechanismPatch.stressTimer);
				}
				else
				{
					EndBlackout(StressMechanismPatch.stressTimer);
				}
			}
			else if (cooldownRemaining > 0f)
			{
				cooldownRemaining -= Time.deltaTime;
			}
			else if (InGameContext())
			{
				float stressTimer = StressMechanismPatch.stressTimer;
				if (stressTimer > 0.4f)
				{
					TryStartBlackout(stressTimer);
				}
			}
		}

		private void CreateVolume()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("StressVignetteVolume");
			val.transform.SetParent(((Component)this).transform, false);
			stressVolume = val.AddComponent<Volume>();
			stressVolume.isGlobal = true;
			stressVolume.priority = 100f;
			stressVolume.weight = 0f;
			VolumeProfile val2 = ScriptableObject.CreateInstance<VolumeProfile>();
			stressVolume.profile = val2;
			vignette = val2.Add<Vignette>(true);
			((VolumeParameter<VignetteMode>)(object)vignette.mode).Override((VignetteMode)0);
			((VolumeParameter<Color>)(object)vignette.color).Override(Color.black);
			((VolumeParameter<Vector2>)(object)vignette.center).Override(new Vector2(0.5f, 0.5f));
			((VolumeParameter<float>)(object)vignette.intensity).Override(0f);
			((VolumeParameter<float>)(object)vignette.smoothness).Override(0.6f);
			((VolumeParameter<float>)(object)vignette.roundness).Override(1f);
			((VolumeParameter<float>)(object)vignette.opacity).Override(1f);
			colorAdjustments = val2.Add<ColorAdjustments>(true);
			((VolumeParameter<float>)(object)colorAdjustments.postExposure).Override(0f);
			((VolumeParameter)colorAdjustments.saturation).overrideState = false;
		}

		private bool InGameContext()
		{
			if (!BalanceTweaksPlugin.EnableStressMechanism.Value)
			{
				return false;
			}
			if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.inShipPhase)
			{
				return false;
			}
			PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
			if ((Object)(object)val != (Object)null)
			{
				return !val.isPlayerDead;
			}
			return false;
		}

		private void TryStartBlackout(float stress)
		{
			float num = Mathf.InverseLerp(0.4f, 1f, stress);
			float num2 = Mathf.Lerp(0.01f, 0.225f, num) * Time.deltaTime;
			if (Random.value < num2)
			{
				blackoutActive = true;
				blackoutTimer = 0f;
				blackoutDuration = 12f;
				audio.PlayBlackoutSound();
			}
		}

		private void UpdateBlackout(float stress)
		{
			blackoutTimer += Time.deltaTime;
			ApplyDepth(1f, stress);
			if (blackoutTimer >= blackoutDuration)
			{
				EndBlackout(stress);
			}
		}

		private void ApplyDepth(float alpha, float stress)
		{
			((VolumeParameter<float>)(object)vignette.intensity).Override(0.85f * alpha);
			((VolumeParameter<float>)(object)colorAdjustments.postExposure).Override(-1f * alpha);
			stressVolume.weight = 1f;
		}

		private void EndBlackout(float stress)
		{
			if (blackoutActive)
			{
				blackoutActive = false;
				((VolumeParameter<float>)(object)vignette.intensity).Override(0f);
				((VolumeParameter<float>)(object)colorAdjustments.postExposure).Override(0f);
				stressVolume.weight = 0f;
				audio.StopBlackoutSound();
				float num = Mathf.InverseLerp(0.4f, 1f, stress);
				cooldownRemaining = Mathf.Lerp(80f, 40f, num);
			}
		}
	}
	internal class TinnitusEffect : MonoBehaviour
	{
		private const float DeafenDecibels = -80f;

		private const float HallucinationMuteDelay = 5f;

		private const float TinnitusThreshold = 0.2f;

		private const float HallucinationThreshold = 0.65f;

		private const float MinChancePerSecond = 0.01f;

		private const float MaxChancePerSecond = 0.25f;

		private const float CooldownAtThreshold = 70f;

		private const float CooldownAtMaxStress = 35f;

		private const float TinnitusDuration = 5f;

		private const float HallucinationDuration = 10f;

		private AudioManager audio;

		private bool tinnitusActive;

		private float soundRemaining;

		private float muteDelayRemaining;

		private float cooldownRemaining;

		private void Awake()
		{
			audio = ((Component)this).GetComponent<AudioManager>();
		}

		private void Update()
		{
			if (tinnitusActive)
			{
				if (InGameContext())
				{
					UpdateActiveTinnitus();
				}
				else
				{
					EndTinnitus(StressMechanismPatch.stressTimer);
				}
			}
			else if (cooldownRemaining > 0f)
			{
				cooldownRemaining -= Time.deltaTime;
			}
			else
			{
				if (!InGameContext())
				{
					return;
				}
				float stressTimer = StressMechanismPatch.stressTimer;
				if (stressTimer > 0.2f)
				{
					float num = Mathf.InverseLerp(0.2f, 1f, stressTimer);
					float num2 = Mathf.Lerp(0.01f, 0.25f, num) * Time.deltaTime;
					if (Random.value < num2)
					{
						StartTinnitus(stressTimer);
					}
				}
			}
		}

		private void OnDisable()
		{
			EndTinnitus(StressMechanismPatch.stressTimer);
		}

		private bool InGameContext()
		{
			if (!BalanceTweaksPlugin.EnableStressMechanism.Value)
			{
				return false;
			}
			if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.inShipPhase)
			{
				return false;
			}
			PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
			if ((Object)(object)val != (Object)null)
			{
				return !val.isPlayerDead;
			}
			return false;
		}

		private void StartTinnitus(float stress)
		{
			tinnitusActive = true;
			if (stress >= 0.65f && IsInsideFactory() && Random.value < 0.5f)
			{
				soundRemaining = 10f;
				muteDelayRemaining = 5f;
				audio.PlayHallucinationSound();
			}
			else
			{
				soundRemaining = 5f;
				muteDelayRemaining = 0f;
				audio.PlayTinnitusSound();
			}
		}

		private void UpdateActiveTinnitus()
		{
			soundRemaining -= Time.deltaTime;
			if (muteDelayRemaining > 0f)
			{
				muteDelayRemaining -= Time.deltaTime;
			}
			else
			{
				ApplyMute();
			}
			if (soundRemaining <= 0f)
			{
				EndTinnitus(StressMechanismPatch.stressTimer);
			}
		}

		private void ApplyMute()
		{
			if ((Object)(object)SoundManager.Instance != (Object)null)
			{
				SoundManager.Instance.SetDiageticMasterVolume(-80f);
			}
			audio.SetDesaturateSoundMuted(muted: true);
			if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)GameNetworkManager.Instance == (Object)null)
			{
				return;
			}
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)GameNetworkManager.Instance.localPlayerController) && (Object)(object)val.currentVoiceChatIngameSettings != (Object)null && (Object)(object)val.currentVoiceChatIngameSettings.voiceAudio != (Object)null)
				{
					val.currentVoiceChatIngameSettings.voiceAudio.mute = true;
				}
			}
		}

		private static bool IsInsideFactory()
		{
			if ((Object)(object)GameNetworkManager.Instance != (Object)null && (Object)(object)GameNetworkManager.Instance.localPlayerController != (Object)null)
			{
				return GameNetworkManager.Instance.localPlayerController.isInsideFactory;
			}
			return false;
		}

		private void EndTinnitus(float stress)
		{
			if (!tinnitusActive)
			{
				return;
			}
			tinnitusActive = false;
			soundRemaining = 0f;
			muteDelayRemaining = 0f;
			audio.StopTinnitusSound();
			audio.StopHallucinationSound();
			audio.SetDesaturateSoundMuted(muted: false);
			float num = Mathf.InverseLerp(0.2f, 1f, stress);
			cooldownRemaining = Mathf.Lerp(70f, 35f, num);
			if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)GameNetworkManager.Instance == (Object)null)
			{
				return;
			}
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)GameNetworkManager.Instance.localPlayerController) && (Object)(object)val.currentVoiceChatIngameSettings != (Object)null && (Object)(object)val.currentVoiceChatIngameSettings.voiceAudio != (Object)null)
				{
					val.currentVoiceChatIngameSettings.voiceAudio.mute = false;
				}
			}
		}
	}
}