Decompiled source of RealHeartAttack v1.2.3

HeartAttack.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Coroner;
using GameNetcodeStuff;
using HarmonyLib;
using HeartAttack.Patches;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("HeartAttack")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("HeartAttack")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("f58e7f15-ddcf-41ab-a659-59dc598c291f")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace HeartAttack
{
	[BepInPlugin("Turkeysteaks.HeartAttackMod", "Real Heart Attack", "1.2.3")]
	public class Plugin : BaseUnityPlugin
	{
		private const string modGUID = "Turkeysteaks.HeartAttackMod";

		private const string modName = "Real Heart Attack";

		private const string modVersion = "1.2.3";

		private readonly Harmony harmony = new Harmony("Turkeysteaks.HeartAttackMod");

		private static Plugin Instance;

		internal static ManualLogSource Logger;

		internal static HeartAttackConfig BoundConfig { get; private set; }

		private void Awake()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
			BoundConfig = new HeartAttackConfig(((BaseUnityPlugin)this).Config);
			Logger = ((BaseUnityPlugin)this).Logger;
			Logger.LogInfo((object)"OH MY LORD!");
			harmony.PatchAll(typeof(Plugin));
			harmony.PatchAll(typeof(PlayerControllerBPatch));
			if (CoronerCompatibility.enabled)
			{
				CoronerCompatibility.CoronerRegister();
			}
		}
	}
}
namespace HeartAttack.Patches
{
	public class CoronerCompatibility
	{
		private static bool? _enabled;

		private static string HEART_ATTACK_LANGUAGE_KEY = "DeathHeartAttack";

		private static AdvancedCauseOfDeath HEART_ATTACK;

		public static bool enabled
		{
			get
			{
				if (!_enabled.HasValue)
				{
					_enabled = Chainloader.PluginInfos.ContainsKey("com.elitemastereric.coroner");
				}
				return _enabled.Value;
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		public static void CoronerRegister()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (!API.IsRegistered(HEART_ATTACK_LANGUAGE_KEY))
			{
				HEART_ATTACK = API.Register(HEART_ATTACK_LANGUAGE_KEY);
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		public static void CoronerSetCauseOfDeathHeartAttack(PlayerControllerB player)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			API.SetCauseOfDeath(player, (AdvancedCauseOfDeath?)HEART_ATTACK);
		}
	}
	public class HeartAttackConfig
	{
		public readonly ConfigEntry<float> heartAttackChance;

		public readonly ConfigEntry<float> trembleChance;

		public readonly ConfigEntry<float> adrenalineChance;

		public readonly ConfigEntry<float> minFearToTrigger;

		public readonly ConfigEntry<float> maxFearToReset;

		public readonly ConfigEntry<bool> heartAttackWhenAlone;

		public readonly ConfigEntry<bool> trembleAfterAdrenaline;

		public readonly ConfigEntry<bool> trembleInstant;

		public readonly ConfigEntry<float> playerTrembleMoveSpeed;

		public readonly ConfigEntry<float> playerTrembleClimbSpeed;

		public readonly ConfigEntry<float> playerTrembleTime;

		public readonly ConfigEntry<bool> trembleDrainsStamina;

		public readonly ConfigEntry<bool> adrenalineInstant;

		public readonly ConfigEntry<float> adrenalineMoveSpeed;

		public readonly ConfigEntry<float> adrenalineClimbSpeed;

		public readonly ConfigEntry<float> adrenalineTime;

		public readonly ConfigEntry<float> adrenalineFOV;

		public readonly ConfigEntry<float> adrenalineDrunkness;

		public HeartAttackConfig(ConfigFile cfg)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Expected O, but got Unknown
			cfg.SaveOnConfigSet = false;
			heartAttackChance = cfg.Bind<float>("General", "HeartAttackChance", 5f, new ConfigDescription("Percentage chance to have a heart attack on fear. Set to 0 for no chance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			trembleChance = cfg.Bind<float>("General", "TrembleChance", 13f, new ConfigDescription("Percentage chance to tremble on fear. Set to 0 for no chance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			adrenalineChance = cfg.Bind<float>("General", "AdrenalineChance", 15f, new ConfigDescription("Percentage chance to gain an adrenaline rush on fear. Set to 0 for no chance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			minFearToTrigger = cfg.Bind<float>("General", "FearToTrigger", 0.5f, "Minimum fear required to trigger any of the effects. Value should be between 0 and 1, and must be higher than FearToReset.");
			maxFearToReset = cfg.Bind<float>("General", "FearToReset", 0.25f, "Maximum fear required to reset the chance to have an effect. Once fear is below this number, getting scared again can trigger another effect. Value should be between 0 and 1, and must be lower than FearToTrigger.");
			heartAttackWhenAlone = cfg.Bind<bool>("General", "HeartAttackWhenAlone", false, "Whether it's possible to have a heart attack when on your own. Note that in singleplayer, this value is ignored and you can always have a heart attack.");
			trembleAfterAdrenaline = cfg.Bind<bool>("Adrenaline", "TrembleAfterAdrenaline", false, "Whether to always force a tremble (slowdown) after an adrenaline rush.");
			trembleInstant = cfg.Bind<bool>("Tremble", "TrembleIsInstant", true, "Whether tremble's effects happen instantly or are gradually started and ended.");
			trembleDrainsStamina = cfg.Bind<bool>("Tremble", "TrembleDrainsStamina", true, "Whether tremble drains stamina.");
			playerTrembleMoveSpeed = cfg.Bind<float>("Tremble", "TrembleMoveSpeed", 0.5f, "Speed the player walks while trembling.");
			playerTrembleClimbSpeed = cfg.Bind<float>("Tremble", "TrembleClimbSpeed", 2f, "Speed the player climbs while trembling");
			playerTrembleTime = cfg.Bind<float>("Tremble", "TrembleTime", 2.5f, "Time (in seconds) the player trembles for.");
			adrenalineInstant = cfg.Bind<bool>("Adrenaline", "AdrenalineIsInstant", false, "Whether adrenaline's effects happen instantly or are gradually started and ended.");
			adrenalineMoveSpeed = cfg.Bind<float>("Adrenaline", "AdrenalineMoveSpeed", 7f, "Speed the player walks with adrenaline.");
			adrenalineClimbSpeed = cfg.Bind<float>("Adrenaline", "AdrenalineClimbSpeed", 4f, "Speed the player climbs with adrenaline.");
			adrenalineTime = cfg.Bind<float>("Adrenaline", "AdrenalineTime", 3f, "Time (in seconds) the player is affected by the adrenaline rush.");
			adrenalineFOV = cfg.Bind<float>("Adrenaline", "AdrenalineFOV", 72f, "(Currently not used) Field of View to use while affected by the adrenaline rush.");
			adrenalineDrunkness = cfg.Bind<float>("Adrenaline", "AdrenalineExtraDrunkness", 0.6f, "How much 'drunkness' to add to the player when hit with adrenaline.");
			ClearOrphanedEntries(cfg);
			cfg.Save();
			cfg.SaveOnConfigSet = true;
		}

		private static void ClearOrphanedEntries(ConfigFile cfg)
		{
			PropertyInfo propertyInfo = AccessTools.Property(typeof(ConfigFile), "OrphanedEntries");
			Dictionary<ConfigDefinition, string> dictionary = (Dictionary<ConfigDefinition, string>)propertyInfo.GetValue(cfg);
			dictionary.Clear();
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB))]
	internal class PlayerControllerBPatch
	{
		private static bool hasHeartAttackOccurred = false;

		private static bool hasFearAttackOccurred = false;

		private static bool hasAdrenalineOccurred = false;

		private static bool trembling = false;

		private static bool adrenaline = false;

		private static float minFearToTrigger = 0.5f;

		private static float maxFearToReset = 0.25f;

		private static bool heartAttackWhenAlone = false;

		private static float heartAttackChance = 10f;

		private static float trembleChance = 13f;

		private static bool trembleInstant = true;

		private static float trembleMoveSpeed = 0.35f;

		private static float trembleClimbSpeed = 2f;

		private static float trembleTime = 2.5f;

		private static bool trembleDrainsStamina = true;

		private static float adrenalineChance = 10f;

		private static bool adrenalineInstant = false;

		private static float adrenalineMoveSpeed = 1.5f;

		private static float adrenalineClimbSpeed = 4f;

		private static float adrenalineTime = 2.5f;

		private static float adrenalineFOV = 72f;

		private static float adrenalineDrunkness = 5f;

		private static bool trembleAfterAdrenaline = false;

		private static bool hasSetVals = false;

		[HarmonyPatch("Update")]
		[HarmonyPostfix]
		private static void HeartAttack(PlayerControllerB __instance)
		{
			if (!((Object)(object)__instance == (Object)(object)GameNetworkManager.Instance.localPlayerController))
			{
				return;
			}
			if (!hasSetVals)
			{
				heartAttackChance = Plugin.BoundConfig.heartAttackChance.Value;
				trembleChance = Plugin.BoundConfig.trembleChance.Value;
				adrenalineChance = Plugin.BoundConfig.adrenalineChance.Value;
				minFearToTrigger = Plugin.BoundConfig.minFearToTrigger.Value;
				maxFearToReset = Plugin.BoundConfig.maxFearToReset.Value;
				heartAttackWhenAlone = Plugin.BoundConfig.heartAttackWhenAlone.Value;
				trembleInstant = Plugin.BoundConfig.trembleInstant.Value;
				trembleMoveSpeed = Plugin.BoundConfig.playerTrembleMoveSpeed.Value;
				trembleClimbSpeed = Plugin.BoundConfig.playerTrembleClimbSpeed.Value;
				trembleTime = Plugin.BoundConfig.playerTrembleTime.Value;
				trembleDrainsStamina = Plugin.BoundConfig.trembleDrainsStamina.Value;
				adrenalineInstant = Plugin.BoundConfig.adrenalineInstant.Value;
				adrenalineMoveSpeed = Plugin.BoundConfig.adrenalineMoveSpeed.Value;
				adrenalineClimbSpeed = Plugin.BoundConfig.adrenalineClimbSpeed.Value;
				adrenalineTime = Plugin.BoundConfig.adrenalineTime.Value;
				adrenalineFOV = Plugin.BoundConfig.adrenalineFOV.Value;
				adrenalineDrunkness = Plugin.BoundConfig.adrenalineDrunkness.Value;
				trembleAfterAdrenaline = Plugin.BoundConfig.trembleAfterAdrenaline.Value;
				hasSetVals = true;
			}
			int num = StartOfRound.Instance.allPlayerScripts.Count((PlayerControllerB x) => x.isPlayerControlled);
			if (StartOfRound.Instance.fearLevel >= minFearToTrigger)
			{
				if (!hasHeartAttackOccurred && (num <= 1 || !__instance.isPlayerAlone || heartAttackWhenAlone))
				{
					TriggerHeartAttack(__instance);
				}
				else if (!hasFearAttackOccurred)
				{
					TriggerTremblingFear(__instance);
				}
				else if (!hasAdrenalineOccurred)
				{
					TriggerAdrenaline(__instance);
				}
			}
			else if (StartOfRound.Instance.fearLevel < maxFearToReset)
			{
				hasHeartAttackOccurred = false;
				hasFearAttackOccurred = false;
				hasAdrenalineOccurred = false;
			}
		}

		private static void TriggerHeartAttack(PlayerControllerB player)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			float num = Random.Range(0f, 100f);
			float num2 = heartAttackChance;
			Plugin.Logger.LogDebug((object)$"Heart Attack Trigger Value: {num}");
			if (num <= num2)
			{
				player.KillPlayer(Vector3.zero, true, (CauseOfDeath)0, 0, Vector3.zero);
				if (CoronerCompatibility.enabled)
				{
					CoronerCompatibility.CoronerRegister();
					CoronerCompatibility.CoronerSetCauseOfDeathHeartAttack(player);
				}
				Plugin.Logger.LogDebug((object)"HEART ATTACK");
			}
			hasHeartAttackOccurred = true;
		}

		private static void TriggerTremblingFear(PlayerControllerB player, bool force = false)
		{
			float num = Random.Range(0f, 100f);
			float num2 = trembleChance;
			Plugin.Logger.LogDebug((object)$"Tremble Trigger Value: {num}");
			if ((!trembling && !adrenaline && num <= num2) || force)
			{
				Plugin.Logger.LogDebug((object)"FEAR!");
				((MonoBehaviour)player).StartCoroutine(ApplyTheFear(player));
			}
			hasFearAttackOccurred = true;
		}

		private static void TriggerAdrenaline(PlayerControllerB player)
		{
			float num = Random.Range(0f, 100f);
			float num2 = adrenalineChance;
			Plugin.Logger.LogDebug((object)$"Adrenaline Trigger Value: {num}");
			if (!adrenaline && !trembling && num <= num2)
			{
				Plugin.Logger.LogDebug((object)"ADRENALINE!");
				((MonoBehaviour)player).StartCoroutine(ApplyTheAdrenaline(player));
			}
			hasAdrenalineOccurred = true;
		}

		private static IEnumerator ApplyTheFear(PlayerControllerB player)
		{
			trembling = true;
			float originalMovementSpeed = player.movementSpeed;
			float originalClimbSpeed = player.climbSpeed;
			HUDManager.Instance.ShakeCamera((ScreenShakeType)1);
			if (trembleInstant)
			{
				player.movementSpeed = trembleMoveSpeed;
				player.climbSpeed = trembleClimbSpeed;
				if (trembleDrainsStamina)
				{
					player.sprintMeter = 0f;
				}
				yield return (object)new WaitForSeconds(trembleTime);
			}
			else
			{
				float trembleTimeInc = trembleTime / 20f;
				float trembleSprintDrainMod = 0.5f;
				for (int j = 0; j < 15; j++)
				{
					player.movementSpeed = Mathf.Lerp(originalMovementSpeed, trembleMoveSpeed, (float)j / 15f);
					player.climbSpeed = Mathf.Lerp(originalClimbSpeed, trembleClimbSpeed, (float)j / 15f);
					yield return (object)new WaitForSeconds(trembleTimeInc);
					if (trembleDrainsStamina)
					{
						player.sprintMeter -= trembleTimeInc * trembleSprintDrainMod;
					}
				}
				for (int i = 0; i < 5; i++)
				{
					player.movementSpeed = Mathf.Lerp(trembleMoveSpeed, originalMovementSpeed, (float)i / 5f);
					player.climbSpeed = Mathf.Lerp(trembleClimbSpeed, originalClimbSpeed, (float)i / 5f);
					yield return (object)new WaitForSeconds(trembleTimeInc);
					if (trembleDrainsStamina)
					{
						player.sprintMeter -= trembleTimeInc * trembleSprintDrainMod * 0.5f;
					}
				}
			}
			player.movementSpeed = originalMovementSpeed;
			player.climbSpeed = originalClimbSpeed;
			trembling = false;
		}

		private static IEnumerator ApplyTheAdrenaline(PlayerControllerB player)
		{
			adrenaline = true;
			float originalMovementSpeed = player.movementSpeed;
			float originalClimbSpeed = player.climbSpeed;
			float originalFOV = player.targetFOV;
			float originalDrunkness = player.drunkness;
			if (adrenalineInstant)
			{
				player.movementSpeed = adrenalineMoveSpeed;
				player.climbSpeed = adrenalineClimbSpeed;
				player.drunkness = adrenalineDrunkness;
				yield return (object)new WaitForSeconds(adrenalineTime);
			}
			else
			{
				float adrenalineTimeInc = adrenalineTime / 20f;
				for (int j = 0; j < 15; j++)
				{
					player.movementSpeed = Mathf.Lerp(originalMovementSpeed, adrenalineMoveSpeed, (float)j / 15f);
					player.climbSpeed = Mathf.Lerp(originalClimbSpeed, adrenalineClimbSpeed, (float)j / 15f);
					player.drunkness = Mathf.Lerp(originalDrunkness, adrenalineDrunkness, (float)j / 15f);
					yield return (object)new WaitForSeconds(adrenalineTimeInc);
				}
				for (int i = 0; i < 5; i++)
				{
					player.movementSpeed = Mathf.Lerp(adrenalineMoveSpeed, originalMovementSpeed, (float)i / 5f);
					player.climbSpeed = Mathf.Lerp(adrenalineClimbSpeed, originalClimbSpeed, (float)i / 5f);
					player.drunkness = Mathf.Lerp(adrenalineDrunkness, originalDrunkness, (float)i / 5f);
					yield return (object)new WaitForSeconds(adrenalineTimeInc);
				}
			}
			player.movementSpeed = originalMovementSpeed;
			player.climbSpeed = originalClimbSpeed;
			player.targetFOV = originalFOV;
			player.drunkness = originalDrunkness;
			if (trembleAfterAdrenaline)
			{
				TriggerTremblingFear(player, force: true);
			}
			adrenaline = false;
		}
	}
}