Decompiled source of Bleeding v0.1.0

BepInEx\plugins\BleedingMod\BleedingMod.dll

Decompiled a day ago
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BleedingMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("BleedingMod")]
[assembly: AssemblyTitle("BleedingMod")]
[assembly: AssemblyVersion("0.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BleedingMod
{
	[BepInPlugin("com.tambistudios.bleeding", "Bleeding", "0.1.0")]
	public class BleedingPlugin : BaseUnityPlugin
	{
		public const string MOD_GUID = "com.tambistudios.bleeding";

		public const string MOD_NAME = "Bleeding";

		public const string MOD_VERSION = "0.1.0";

		public static BleedingPlugin Instance;

		public static ManualLogSource Logger;

		public const float THRESHOLD_NORMAL = 20f;

		public const float THRESHOLD_LOW = 30f;

		public const float THRESHOLD_HIGH = 10f;

		public const float DURATION_NORMAL = 30f;

		public const float DURATION_LOW = 20f;

		public const float DURATION_HIGH = 60f;

		internal static readonly Color ColRed = new Color(0.85f, 0.05f, 0.05f, 1f);

		internal static readonly Color ColBrt = new Color(1f, 0.25f, 0.25f, 1f);

		private Texture2D _guiTex;

		private Texture2D _dropTex;

		private float _pulseTimer;

		private float _flashTimer;

		private void Awake()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			new Harmony("com.tambistudios.bleeding").PatchAll();
			Logger.LogInfo((object)"[Bleeding 0.1.0] Loaded.");
		}

		public static float GetFallThreshold()
		{
			try
			{
				float fallDamageMultiplier = Ascents.fallDamageMultiplier;
				if (fallDamageMultiplier <= 0.001f)
				{
					return -1f;
				}
				if (fallDamageMultiplier <= 0.6f)
				{
					return 30f;
				}
				if (fallDamageMultiplier <= 1.5f)
				{
					return 20f;
				}
				return 10f;
			}
			catch
			{
				return 20f;
			}
		}

		public static float GetBleedDuration()
		{
			try
			{
				float fallDamageMultiplier = Ascents.fallDamageMultiplier;
				if (fallDamageMultiplier <= 0.001f)
				{
					return 30f;
				}
				if (fallDamageMultiplier <= 0.6f)
				{
					return 20f;
				}
				if (fallDamageMultiplier <= 1.5f)
				{
					return 30f;
				}
				return 60f;
			}
			catch
			{
				return 30f;
			}
		}

		private void Update()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)localCharacter != (Object)null && (Object)(object)((Component)localCharacter).GetComponent<BleedingTracker>() == (Object)null)
			{
				((Component)localCharacter).gameObject.AddComponent<BleedingTracker>();
			}
			if (Input.GetKeyDown((KeyCode)285) && (Object)(object)localCharacter != (Object)null)
			{
				Rigidbody componentInChildren = ((Component)localCharacter).GetComponentInChildren<Rigidbody>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					Vector3 linearVelocity = componentInChildren.linearVelocity;
					linearVelocity.y = 22f;
					componentInChildren.linearVelocity = linearVelocity;
					Logger.LogInfo((object)"[Bleeding] DEBUG: launched up ~25m");
				}
			}
			BleedingTracker localInstance = BleedingTracker.LocalInstance;
			if ((Object)(object)localInstance != (Object)null && localInstance.isBleeding)
			{
				float num = 0.8f + localInstance.severity * 0.35f;
				_pulseTimer += Time.deltaTime * num;
			}
			else
			{
				_pulseTimer = 0f;
			}
			if (_flashTimer > 0f)
			{
				_flashTimer = Mathf.Max(0f, _flashTimer - Time.deltaTime);
			}
		}

		private static Texture2D LoadDropTexture()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			try
			{
				string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "assets", "blood.png");
				if (File.Exists(path))
				{
					byte[] array = File.ReadAllBytes(path);
					Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
					((Texture)val).filterMode = (FilterMode)1;
					if (ImageConversion.LoadImage(val, array))
					{
						Logger.LogInfo((object)"[Bleeding] Loaded blood.png from assets.");
						return val;
					}
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("[Bleeding] LoadDropTexture: " + ex.Message));
			}
			Logger.LogInfo((object)"[Bleeding] assets/blood.png not found, using procedural drop.");
			return MakeDropTexture(64);
		}

		private static Texture2D MakeDropTexture(int size)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(size, size, (TextureFormat)4, false);
			((Texture)val).filterMode = (FilterMode)1;
			((Texture)val).wrapMode = (TextureWrapMode)1;
			float num = (float)size * 0.5f;
			float num2 = (float)size * 0.42f;
			float num3 = (float)size * 0.3f;
			float num4 = (float)size * 0.94f;
			Color32[] array = (Color32[])(object)new Color32[size * size];
			for (int i = 0; i < size; i++)
			{
				for (int j = 0; j < size; j++)
				{
					float num5 = (float)j + 0.5f;
					float num6 = (float)i + 0.5f;
					float num7 = num5 - num;
					float num8 = num6 - num2;
					bool flag = num7 * num7 + num8 * num8 <= num3 * num3;
					float num9 = ((num6 >= num2 && num6 <= num4) ? ((num4 - num6) / (num4 - num2) * num3) : 0f);
					bool num10 = num6 > num2 && num6 <= num4 && Mathf.Abs(num5 - num) <= num9;
					float num11 = Mathf.Sqrt(num7 * num7 + num8 * num8);
					float num12 = Mathf.Clamp01(1f - (num11 - num3 + 1.5f) / 1.5f);
					byte b = (num10 ? byte.MaxValue : (flag ? byte.MaxValue : ((byte)(num12 * 255f))));
					array[i * size + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, b);
				}
			}
			val.SetPixels32(array);
			val.Apply();
			return val;
		}

		internal void TriggerHurtEffect(Character local)
		{
			_flashTimer = 1f;
			try
			{
				Type typeFromHandle = typeof(IllegalScreenEffect);
				FieldInfo field = typeFromHandle.GetField("character", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				MethodInfo method = typeFromHandle.GetMethod("AddStatus", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2]
				{
					typeof(string),
					typeof(float)
				}, null);
				IllegalScreenEffect[] array = Object.FindObjectsOfType<IllegalScreenEffect>();
				foreach (IllegalScreenEffect obj in array)
				{
					object? obj2 = field?.GetValue(obj);
					if (!((Object)((obj2 is Character) ? obj2 : null) != (Object)(object)local))
					{
						method?.Invoke(obj, new object[2] { "Injury", 1f });
						Logger.LogInfo((object)"[Bleeding] Game hurt screen effect triggered.");
						break;
					}
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("[Bleeding] HurtEffect err: " + ex.Message));
			}
		}

		private void OnGUI()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: 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_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			if ((int)Event.current.type != 7)
			{
				return;
			}
			if ((Object)(object)_guiTex == (Object)null)
			{
				_guiTex = new Texture2D(1, 1);
				_guiTex.SetPixel(0, 0, Color.white);
				_guiTex.Apply();
			}
			Color color = GUI.color;
			BleedingTracker localInstance = BleedingTracker.LocalInstance;
			bool num = (Object)(object)localInstance != (Object)null && localInstance.isBleeding;
			float num2 = _pulseTimer % 1f;
			float num3 = ((num2 < 0.2f) ? (num2 / 0.2f) : (1f - (num2 - 0.2f) / 0.8f));
			if (num)
			{
				float num4 = Mathf.Min(localInstance.severity, 5f);
				float num5 = 0.2f + num4 * 0.03f;
				GUI.color = new Color(0.6f, 0f, 0f, num5 + num3 * 0.04f);
				GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)_guiTex);
			}
			if (_flashTimer > 0f)
			{
				GUI.color = new Color(0.55f, 0f, 0f, _flashTimer * 0.5f);
				GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)_guiTex);
			}
			if (num)
			{
				if ((Object)(object)_dropTex == (Object)null)
				{
					_dropTex = LoadDropTexture();
				}
				if ((Object)(object)_dropTex != (Object)null)
				{
					GUI.color = Color.white;
					GUI.DrawTexture(new Rect((float)Screen.width - 112f, 16f, 96f, 96f), (Texture)(object)_dropTex);
				}
			}
			GUI.color = color;
		}
	}
	public class BleedingTracker : MonoBehaviour
	{
		public static BleedingTracker LocalInstance;

		public static bool s_isBleeding = false;

		public static float s_severity = 0f;

		public static float s_bleedStart = -999f;

		private float _peakFallSpeed;

		private bool _wasFalling;

		private Character _char;

		private Rigidbody _rb;

		private bool _loggedInit;

		public bool isBleeding
		{
			get
			{
				return s_isBleeding;
			}
			set
			{
				s_isBleeding = value;
			}
		}

		public float severity
		{
			get
			{
				return s_severity;
			}
			set
			{
				s_severity = value;
			}
		}

		public float bleedStart
		{
			get
			{
				return s_bleedStart;
			}
			set
			{
				s_bleedStart = value;
			}
		}

		private void Awake()
		{
			_char = ((Component)this).GetComponent<Character>();
			_rb = ((Component)this).GetComponentInChildren<Rigidbody>();
		}

		private void Update()
		{
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_char == (Object)null || (Object)(object)Character.localCharacter != (Object)(object)_char)
			{
				return;
			}
			LocalInstance = this;
			if (!_loggedInit)
			{
				_loggedInit = true;
				BleedingPlugin.Logger.LogInfo((object)("[Bleeding] Tracker active. rb=" + (((Object)(object)_rb != (Object)null) ? ((Object)_rb).name : "NULL")));
			}
			if (s_isBleeding && Time.time - s_bleedStart >= BleedingPlugin.GetBleedDuration())
			{
				s_isBleeding = false;
				s_severity = 0f;
				s_bleedStart = -999f;
				BleedingPlugin.Logger.LogInfo((object)"[Bleeding] Naturally healed.");
			}
			if ((Object)(object)_rb == (Object)null)
			{
				return;
			}
			float y = _rb.linearVelocity.y;
			if (y < -4f)
			{
				_wasFalling = true;
				_peakFallSpeed = Mathf.Max(_peakFallSpeed, 0f - y);
			}
			else
			{
				if (!_wasFalling || !(y > -2f))
				{
					return;
				}
				float num = _peakFallSpeed * _peakFallSpeed / 19.62f;
				float fallThreshold = BleedingPlugin.GetFallThreshold();
				BleedingPlugin.Logger.LogInfo((object)$"[Bleeding] Impact detected: peakSpeed={_peakFallSpeed:F1} m/s, fallH≈{num:F1}m, thresh={fallThreshold}m");
				if (fallThreshold > 0f && num >= fallThreshold)
				{
					float num2 = Mathf.Min(num / fallThreshold, 5f);
					if (!s_isBleeding)
					{
						s_bleedStart = Time.time;
					}
					s_isBleeding = true;
					s_severity = Mathf.Max(s_severity, num2);
					BleedingPlugin.Logger.LogInfo((object)$"[Bleeding] Bleeding triggered! Severity={s_severity:F2}");
					BleedingPlugin.Instance?.TriggerHurtEffect(_char);
				}
				_wasFalling = false;
				_peakFallSpeed = 0f;
			}
		}

		public void CureBleeding()
		{
			if (s_isBleeding)
			{
				s_isBleeding = false;
				s_severity = 0f;
				s_bleedStart = -999f;
				BleedingPlugin.Logger.LogInfo((object)"[Bleeding] Cured by item.");
			}
		}
	}
	[HarmonyPatch(typeof(Character), "Awake")]
	internal static class Patch_Character_Awake
	{
		[HarmonyPostfix]
		private static void Postfix(Character __instance)
		{
			if ((Object)(object)((Component)__instance).GetComponent<BleedingTracker>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<BleedingTracker>();
			}
		}
	}
	[HarmonyPatch(typeof(Character), "CanRegenStamina")]
	internal static class Patch_CanRegenStamina
	{
		[HarmonyPostfix]
		private static void Postfix(Character __instance, ref bool __result)
		{
			if (__instance.IsLocal)
			{
				BleedingTracker component = ((Component)__instance).GetComponent<BleedingTracker>();
				if ((Object)(object)component != (Object)null && component.isBleeding)
				{
					__result = false;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Action_ClearAllStatus), "RunAction")]
	internal static class Patch_ClearAllStatus
	{
		private static readonly FieldInfo _itemField = AccessTools.Field(typeof(Action_ClearAllStatus), "item");

		[HarmonyPostfix]
		private static void Postfix(Action_ClearAllStatus __instance)
		{
			try
			{
				object? obj = _itemField?.GetValue(__instance);
				object? obj2 = ((obj is Item) ? obj : null);
				Character val = ((obj2 != null) ? ((Item)obj2).holderCharacter : null);
				if (!((Object)(object)val == (Object)null) && val.IsLocal)
				{
					((Component)val).GetComponent<BleedingTracker>()?.CureBleeding();
				}
			}
			catch (Exception ex)
			{
				BleedingPlugin.Logger.LogWarning((object)("[Bleeding] ClearAllStatus patch error: " + ex.Message));
			}
		}
	}
}