Decompiled source of Bleeding v1.0.0

BleedingMod\BleedingMod.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

[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("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+2237482c32b5703c2199e5a28b625bd946339c16")]
[assembly: AssemblyProduct("BleedingMod")]
[assembly: AssemblyTitle("BleedingMod")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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
{
	[HarmonyPatch(typeof(CharacterMovement), "GetMovementForce")]
	internal static class CharacterMovement_GetMovementForce_Patch
	{
		[HarmonyPostfix]
		private static void Postfix(CharacterMovement __instance, ref float __result)
		{
			if (__result <= 0f || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			Character component = ((Component)__instance).GetComponent<Character>();
			if (!((Object)(object)component == (Object)null))
			{
				BleedingTracker component2 = ((Component)component).GetComponent<BleedingTracker>();
				if (!((Object)(object)component2 == (Object)null) && component2.isBleeding && component2.level >= BleedLevel.Heavy)
				{
					__result *= 0.85f;
				}
			}
		}
	}
	public class BleedingTracker : MonoBehaviour
	{
		public static BleedingTracker LocalInstance;

		public static bool s_isBleeding = false;

		public static BleedLevel s_level = BleedLevel.None;

		public static float s_bleedStart = -999f;

		public static bool s_isFading = false;

		public static float s_fadeStart = -999f;

		public const float FADE_DURATION = 1.6f;

		private float _peakFallSpeed;

		private bool _wasFalling;

		private Character _char;

		private Rigidbody _rb;

		private BloodTrail _trail;

		private const float REAL_DAMAGE_CHECK_DELAY = 0.35f;

		private float _pendingCheckAt = -1f;

		private float _preFallInjury = -1f;

		private BleedLevel _pendingLevel;

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

		public BleedLevel level
		{
			get
			{
				return s_level;
			}
			set
			{
				s_level = value;
			}
		}

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

		public static float FadeAlpha
		{
			get
			{
				if (s_isBleeding)
				{
					return 1f;
				}
				if (!s_isFading)
				{
					return 0f;
				}
				float num = (Time.time - s_fadeStart) / 1.6f;
				return Mathf.Clamp01(1f - num);
			}
		}

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

		private void Update()
		{
			//IL_00cc: 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 (s_isBleeding && Time.time - s_bleedStart >= BleedingPlugin.GetBleedDuration(s_level))
			{
				CureBleeding();
			}
			if (s_isFading && Time.time - s_fadeStart >= 1.6f)
			{
				s_isFading = false;
				s_level = BleedLevel.None;
			}
			if ((Object)(object)_rb == (Object)null)
			{
				return;
			}
			if (SpiderCheck.IsGrabbedBySpider(_char))
			{
				_wasFalling = false;
				_peakFallSpeed = 0f;
				return;
			}
			bool flag;
			try
			{
				flag = !GameHandler.IsInGameplayScene;
			}
			catch
			{
				flag = false;
			}
			if (flag)
			{
				_wasFalling = false;
				_peakFallSpeed = 0f;
				return;
			}
			float y = _rb.linearVelocity.y;
			bool flag2 = false;
			try
			{
				flag2 = (Object)(object)_char != (Object)null && (Object)(object)_char.data != (Object)null && _char.data.isGrounded;
			}
			catch
			{
			}
			if (y < -4f)
			{
				_wasFalling = true;
				_peakFallSpeed = Mathf.Max(_peakFallSpeed, 0f - y);
			}
			else if (_wasFalling && flag2)
			{
				float fallH = _peakFallSpeed * _peakFallSpeed / 19.62f;
				BleedLevel bleedLevel = BleedingPlugin.ClassifyFall(fallH);
				if (bleedLevel != BleedLevel.None)
				{
					StartBleed(bleedLevel, fallH);
				}
				_wasFalling = false;
				_peakFallSpeed = 0f;
			}
			else if (_wasFalling && y > -2f && !flag2)
			{
				_wasFalling = false;
				_peakFallSpeed = 0f;
			}
		}

		private void StartBleed(BleedLevel lv, float fallH)
		{
			if (!s_isBleeding || lv > s_level)
			{
				s_bleedStart = Time.time;
				s_isBleeding = true;
				s_level = lv;
				BleedingPlugin.Instance?.TriggerHurtEffect(_char);
				ManualLogSource logger = BleedingPlugin.Logger;
				if (logger != null)
				{
					logger.LogInfo((object)string.Format("[Bleeding] {0} → {1}", (fallH > 0f) ? $"Fall {fallH:F1}m" : "confirmed by injury", lv));
				}
			}
		}

		private float GetInjury()
		{
			if ((Object)(object)_char == (Object)null || _char.refs == null || (Object)(object)_char.refs.afflictions == (Object)null)
			{
				return 0f;
			}
			try
			{
				return _char.refs.afflictions.GetCurrentStatus((STATUSTYPE)0);
			}
			catch
			{
				return 0f;
			}
		}

		public void CureBleeding()
		{
			if (s_isBleeding || s_isFading)
			{
				s_isBleeding = false;
				s_bleedStart = -999f;
				s_isFading = true;
				s_fadeStart = Time.time;
			}
		}
	}
	public class BloodPool : MonoBehaviour
	{
		private const float GROW_DURATION = 15f;

		private const float MIN_SCALE = 0.35f;

		private const float MAX_SCALE = 1.9f;

		private const float LIFETIME = 60f;

		private static readonly Queue<BloodPool> _active = new Queue<BloodPool>();

		private const int MAX_ACTIVE_POOLS = 12;

		private float _age;

		private MeshRenderer _mr;

		private MaterialPropertyBlock _mpb;

		public static void TrySpawn(Vector3 origin)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: 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_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			RaycastHit val = default(RaycastHit);
			if (Physics.Raycast(origin + Vector3.up * 1.5f, Vector3.down, ref val, 4f, -1, (QueryTriggerInteraction)1) && (!((Object)(object)((RaycastHit)(ref val)).collider != (Object)null) || !((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Character>() != (Object)null)))
			{
				CreateAt(((RaycastHit)(ref val)).point, ((RaycastHit)(ref val)).normal);
			}
		}

		private static void CreateAt(Vector3 pos, Vector3 normal)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: 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_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = GameObject.CreatePrimitive((PrimitiveType)5);
			Collider component = obj.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			((Object)obj).name = "BleedingMod_BloodPool";
			MeshRenderer component2 = obj.GetComponent<MeshRenderer>();
			((Renderer)component2).receiveShadows = false;
			((Renderer)component2).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)component2).lightProbeUsage = (LightProbeUsage)0;
			((Renderer)component2).reflectionProbeUsage = (ReflectionProbeUsage)0;
			Material val = new Material(Shader.Find("Sprites/Default") ?? Shader.Find("Unlit/Transparent"))
			{
				mainTexture = (Texture)(object)BleedingPlugin.Instance?.GetDropTexture()
			};
			val.SetColor("_Color", new Color(0.35f, 0.02f, 0.02f, 1f));
			val.renderQueue = 3050;
			((Renderer)component2).sharedMaterial = val;
			Transform transform = obj.transform;
			transform.position = pos + normal * 0.015f;
			transform.rotation = Quaternion.LookRotation(-normal) * Quaternion.Euler(0f, Random.Range(0f, 360f), 0f);
			transform.localScale = new Vector3(0.35f, 0.35f, 1f);
			BloodPool item = obj.AddComponent<BloodPool>();
			_active.Enqueue(item);
			while (_active.Count > 12)
			{
				BloodPool bloodPool = _active.Dequeue();
				if ((Object)(object)bloodPool != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)bloodPool).gameObject);
				}
			}
		}

		private void Awake()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			_mr = ((Component)this).GetComponent<MeshRenderer>();
			_mpb = new MaterialPropertyBlock();
		}

		private void Update()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			_age += Time.deltaTime;
			if (_age >= 60f)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			float num = Mathf.Clamp01(_age / 15f);
			float num2 = Mathf.Lerp(0.35f, 1.9f, num);
			((Component)this).transform.localScale = new Vector3(num2, num2, 1f);
			float num3 = ((_age > 55f) ? ((_age - 55f) / 5f) : 0f);
			float num4 = 1f - num3;
			if ((Object)(object)_mr != (Object)null)
			{
				((Renderer)_mr).GetPropertyBlock(_mpb);
				_mpb.SetColor("_Color", new Color(0.35f, 0.02f, 0.02f, num4));
				((Renderer)_mr).SetPropertyBlock(_mpb);
			}
		}
	}
	public class BloodTrail : MonoBehaviour
	{
		private const float MIN_SPEED_TO_DROP = 1.5f;

		private const float RAY_LENGTH = 8f;

		private const float DECAL_LIFT = 0.02f;

		private const float RAY_UP_OFFSET = 2.5f;

		private const float POOL_IDLE_TIME = 2f;

		private const float POOL_COOLDOWN = 5f;

		private static readonly Queue<BloodDrop> _activeDrops = new Queue<BloodDrop>();

		private static Material _sharedMat;

		private Character _char;

		private Rigidbody _rb;

		private float _distanceSinceLast;

		private Vector3 _lastPos;

		private bool _lastPosValid;

		private float _idleTime;

		private float _poolCooldown;

		private AudioSource _audioSrc;

		private AudioClip _dripClip;

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

		private void EnsureAudio()
		{
			if (!((Object)(object)_audioSrc != (Object)null))
			{
				_audioSrc = ((Component)this).gameObject.AddComponent<AudioSource>();
				_audioSrc.playOnAwake = false;
				_audioSrc.spatialBlend = 0f;
				_audioSrc.volume = 0.35f;
				_dripClip = GenerateDripClip();
			}
		}

		private static AudioClip GenerateDripClip()
		{
			int num = 44100;
			int num2 = num / 6;
			float[] array = new float[num2];
			float num3 = 220f;
			for (int i = 0; i < num2; i++)
			{
				float num4 = (float)i / (float)num;
				float num5 = Mathf.Exp((0f - num4) * 22f);
				array[i] = Mathf.Sin(MathF.PI * 2f * num3 * num4) * num5 * 0.6f;
			}
			AudioClip obj = AudioClip.Create("TambiDrip", num2, 1, num, false);
			obj.SetData(array, 0);
			return obj;
		}

		private void Update()
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: 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 || (BleedingPlugin.cfgEnableTrail != null && !BleedingPlugin.cfgEnableTrail.Value))
			{
				return;
			}
			BleedingTracker localInstance = BleedingTracker.LocalInstance;
			if ((Object)(object)localInstance == (Object)null || !localInstance.isBleeding)
			{
				_lastPosValid = false;
				_distanceSinceLast = 0f;
			}
			else
			{
				if ((Object)(object)_rb == (Object)null)
				{
					return;
				}
				Vector3 position = ((Component)_rb).transform.position;
				if (_lastPosValid)
				{
					Vector3 val = position - _lastPos;
					val.y = 0f;
					_distanceSinceLast += ((Vector3)(ref val)).magnitude;
				}
				_lastPos = position;
				_lastPosValid = true;
				Vector2 val2 = new Vector2(_rb.linearVelocity.x, _rb.linearVelocity.z);
				float magnitude = ((Vector2)(ref val2)).magnitude;
				if (_poolCooldown > 0f)
				{
					_poolCooldown -= Time.deltaTime;
				}
				if (magnitude < 0.3f && localInstance.level >= BleedLevel.Heavy)
				{
					_idleTime += Time.deltaTime;
					if (_idleTime >= 2f && _poolCooldown <= 0f)
					{
						BloodPool.TrySpawn(position);
						_poolCooldown = 5f;
						_idleTime = 0f;
					}
				}
				else
				{
					_idleTime = 0f;
				}
				if (magnitude < 1.5f)
				{
					return;
				}
				float intervalMeters = GetIntervalMeters(localInstance.level);
				if (_distanceSinceLast >= intervalMeters)
				{
					_distanceSinceLast = 0f;
					SpawnDrop(position, localInstance.level);
					if ((Object)(object)_audioSrc != (Object)null && (Object)(object)_dripClip != (Object)null && Random.value < 0.35f)
					{
						_audioSrc.PlayOneShot(_dripClip, 0.25f);
					}
				}
			}
		}

		private static float GetIntervalMeters(BleedLevel level)
		{
			return level switch
			{
				BleedLevel.Light => 3.5f, 
				BleedLevel.Medium => 2.2f, 
				BleedLevel.Heavy => 1.2f, 
				BleedLevel.Massive => 0.7f, 
				_ => 3f, 
			};
		}

		private static float GetDropScale(BleedLevel level)
		{
			return level switch
			{
				BleedLevel.Light => 0.4f, 
				BleedLevel.Medium => 0.6f, 
				BleedLevel.Heavy => 0.85f, 
				BleedLevel.Massive => 1.1f, 
				_ => 0.5f, 
			};
		}

		private void SpawnDrop(Vector3 origin, BleedLevel level)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: 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_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: 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_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			RaycastHit[] array = Physics.RaycastAll(origin + Vector3.up * 2.5f, Vector3.down, 8f, -1, (QueryTriggerInteraction)1);
			if (array == null || array.Length == 0)
			{
				return;
			}
			Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
			RaycastHit val = default(RaycastHit);
			bool flag = false;
			RaycastHit[] array2 = array;
			for (int num = 0; num < array2.Length; num++)
			{
				RaycastHit val2 = array2[num];
				if (!((Object)(object)((RaycastHit)(ref val2)).collider == (Object)null) && !((Object)(object)((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent<Character>() != (Object)null))
				{
					val = val2;
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				return;
			}
			EnsureSharedMaterial();
			if ((Object)(object)_sharedMat == (Object)null)
			{
				return;
			}
			GameObject obj = GameObject.CreatePrimitive((PrimitiveType)5);
			Collider component = obj.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			((Object)obj).name = "BleedingMod_BloodDrop";
			MeshRenderer component2 = obj.GetComponent<MeshRenderer>();
			((Renderer)component2).sharedMaterial = _sharedMat;
			((Renderer)component2).receiveShadows = false;
			((Renderer)component2).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)component2).lightProbeUsage = (LightProbeUsage)0;
			((Renderer)component2).reflectionProbeUsage = (ReflectionProbeUsage)0;
			Transform transform = obj.transform;
			transform.position = ((RaycastHit)(ref val)).point + ((RaycastHit)(ref val)).normal * 0.02f;
			transform.rotation = Quaternion.LookRotation(-((RaycastHit)(ref val)).normal) * Quaternion.Euler(0f, Random.Range(0f, 360f), 0f);
			float num2 = GetDropScale(level) * Random.Range(0.85f, 1.15f);
			transform.localScale = new Vector3(num2, num2, num2);
			float lifetime = ((BleedingPlugin.cfgTrailLifetime != null) ? BleedingPlugin.cfgTrailLifetime.Value : 25f);
			BloodDrop bloodDrop = obj.AddComponent<BloodDrop>();
			bloodDrop.Init(lifetime);
			_activeDrops.Enqueue(bloodDrop);
			int num3 = ((BleedingPlugin.cfgMaxTrailDrops != null) ? BleedingPlugin.cfgMaxTrailDrops.Value : 40);
			while (_activeDrops.Count > num3)
			{
				BloodDrop bloodDrop2 = _activeDrops.Dequeue();
				if ((Object)(object)bloodDrop2 != (Object)null)
				{
					bloodDrop2.ForceFadeOut();
				}
			}
		}

		private static void EnsureSharedMaterial()
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_sharedMat != (Object)null)
			{
				return;
			}
			Texture2D val = BleedingPlugin.Instance?.GetDropTexture();
			if (!((Object)(object)val == (Object)null))
			{
				Shader val2 = Shader.Find("Sprites/Default") ?? Shader.Find("Unlit/Transparent") ?? Shader.Find("Legacy Shaders/Transparent/Diffuse");
				if (!((Object)(object)val2 == (Object)null))
				{
					_sharedMat = new Material(val2)
					{
						mainTexture = (Texture)(object)val
					};
					_sharedMat.SetColor("_Color", new Color(0.55f, 0.02f, 0.02f, 1f));
					_sharedMat.renderQueue = 3100;
				}
			}
		}
	}
	public class BloodDrop : MonoBehaviour
	{
		private float _totalLife;

		private float _elapsed;

		private MaterialPropertyBlock _mpb;

		private MeshRenderer _mr;

		private Color _baseColor = new Color(0.55f, 0.02f, 0.02f, 1f);

		public void Init(float lifetime)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			_totalLife = Mathf.Max(1f, lifetime);
			_mr = ((Component)this).GetComponent<MeshRenderer>();
			_mpb = new MaterialPropertyBlock();
		}

		public void ForceFadeOut()
		{
			_elapsed = _totalLife - 1f;
		}

		private void Update()
		{
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			_elapsed += Time.deltaTime;
			if (_elapsed >= _totalLife)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			float num = _elapsed / _totalLife;
			float num2 = ((num < 0.75f) ? 1f : Mathf.Lerp(1f, 0f, (num - 0.75f) / 0.25f));
			if ((Object)(object)_mr != (Object)null && _mpb != null)
			{
				((Renderer)_mr).GetPropertyBlock(_mpb);
				_mpb.SetColor("_Color", new Color(_baseColor.r, _baseColor.g, _baseColor.b, num2));
				((Renderer)_mr).SetPropertyBlock(_mpb);
			}
		}
	}
	[HarmonyPatch(typeof(Action_ModifyStatus), "RunAction")]
	internal static class Patch_ModifyStatus_HealInjury
	{
		private static readonly FieldInfo _itemField = AccessTools.Field(typeof(ItemAction), "item") ?? AccessTools.Field(typeof(Action_ModifyStatus), "item");

		[HarmonyPostfix]
		private static void Postfix(Action_ModifyStatus __instance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((int)__instance.statusType == 0 && !(__instance.changeAmount >= 0f))
				{
					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] ModifyStatus heal: " + ex.Message));
			}
		}
	}
	[BepInPlugin("com.tambistudios.bleeding", "Bleeding", "1.0.0")]
	public class BleedingPlugin : BaseUnityPlugin
	{
		public const string MOD_GUID = "com.tambistudios.bleeding";

		public const string MOD_NAME = "Bleeding";

		public const string MOD_VERSION = "1.0.0";

		public static BleedingPlugin Instance;

		public static ManualLogSource Logger;

		public const float BASE_THRESHOLD_LIGHT = 10f;

		public const float BASE_THRESHOLD_MEDIUM = 20f;

		public const float BASE_THRESHOLD_HEAVY = 30f;

		public const float DURATION_LIGHT = 15f;

		public const float DURATION_MEDIUM = 30f;

		public const float DURATION_HEAVY = 60f;

		public const float DURATION_MASSIVE = 120f;

		public const float HARDCODED_MASSIVE_HEIGHT = 160f;

		public static ConfigEntry<bool> cfgEnableTrail;

		public static ConfigEntry<float> cfgTrailLifetime;

		public static ConfigEntry<int> cfgMaxTrailDrops;

		public static ConfigEntry<float> cfgOverlayIntensity;

		public const float HARDCODED_LIGHT_HEIGHT = 32f;

		public const float HARDCODED_MEDIUM_HEIGHT = 64f;

		public const float HARDCODED_HEAVY_HEIGHT = 96f;

		public const bool HARDCODED_REQUIRE_REAL_FALL_DAMAGE = true;

		public const float HARDCODED_MIN_INJURY_TO_BLEED = 0.02f;

		private Texture2D _guiTex;

		private Texture2D _dropTex;

		private float _pulseTimer;

		private float _flashTimer;

		private static readonly MethodInfo _addIllegalStatus = typeof(Character).GetMethod("AddIllegalStatus", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private void Awake()
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			cfgEnableTrail = ((BaseUnityPlugin)this).Config.Bind<bool>("Trail", "EnableBloodTrail", true, "Whether bleeding leaves blood drops on the ground while you move.");
			cfgTrailLifetime = ((BaseUnityPlugin)this).Config.Bind<float>("Trail", "DropLifetimeSeconds", 25f, "How long each blood drop stays visible before fading (seconds).");
			cfgMaxTrailDrops = ((BaseUnityPlugin)this).Config.Bind<int>("Trail", "MaxActiveDrops", 40, "Maximum number of blood drops on the ground at once. Older drops fade first.");
			cfgOverlayIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "ScreenOverlayIntensity", 1f, "Red screen overlay intensity while bleeding. Set 0 to disable for motion sickness comfort.");
			new Harmony("com.tambistudios.bleeding").PatchAll();
			Logger.LogInfo((object)"[Bleeding 1.0.0] Loaded.");
		}

		public static float GetScaledThreshold(BleedLevel level)
		{
			float num;
			switch (TambiAfflictionOption.GetValue("Bleeding"))
			{
			case 0:
				return -1f;
			case 1:
				num = 0.6f;
				break;
			case 2:
				num = 1f;
				break;
			case 3:
				num = 1.5f;
				break;
			default:
				num = 1f;
				break;
			}
			float num2 = num;
			float num3 = level switch
			{
				BleedLevel.Light => 32f, 
				BleedLevel.Medium => 64f, 
				BleedLevel.Heavy => 96f, 
				BleedLevel.Massive => 160f, 
				_ => 64f, 
			};
			if (num2 <= 0.6f)
			{
				return num3 * 1.5f;
			}
			if (num2 <= 1.5f)
			{
				return num3;
			}
			return num3 * 0.5f;
		}

		public static float GetBleedDuration(BleedLevel level)
		{
			return level switch
			{
				BleedLevel.Light => 15f, 
				BleedLevel.Medium => 30f, 
				BleedLevel.Heavy => 60f, 
				BleedLevel.Massive => 120f, 
				_ => 30f, 
			};
		}

		public static BleedLevel ClassifyFall(float fallH)
		{
			float scaledThreshold = GetScaledThreshold(BleedLevel.Massive);
			float scaledThreshold2 = GetScaledThreshold(BleedLevel.Heavy);
			float scaledThreshold3 = GetScaledThreshold(BleedLevel.Medium);
			float scaledThreshold4 = GetScaledThreshold(BleedLevel.Light);
			if (scaledThreshold > 0f && fallH >= scaledThreshold)
			{
				return BleedLevel.Massive;
			}
			if (scaledThreshold2 > 0f && fallH >= scaledThreshold2)
			{
				return BleedLevel.Heavy;
			}
			if (scaledThreshold3 > 0f && fallH >= scaledThreshold3)
			{
				return BleedLevel.Medium;
			}
			if (scaledThreshold4 > 0f && fallH >= scaledThreshold4)
			{
				return BleedLevel.Light;
			}
			return BleedLevel.None;
		}

		private void Update()
		{
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)localCharacter != (Object)null && (Object)(object)((Component)localCharacter).GetComponent<BleedingTracker>() == (Object)null)
			{
				((Component)localCharacter).gameObject.AddComponent<BleedingTracker>();
			}
			BleedingTracker localInstance = BleedingTracker.LocalInstance;
			if ((Object)(object)localInstance != (Object)null && localInstance.isBleeding)
			{
				_pulseTimer += Time.deltaTime * (0.8f + (float)localInstance.level * 0.25f);
			}
			else
			{
				_pulseTimer = 0f;
			}
			if (_flashTimer > 0f)
			{
				_flashTimer = Mathf.Max(0f, _flashTimer - Time.deltaTime);
			}
		}

		internal void TriggerHurtEffect(Character local)
		{
			_flashTimer = 1f;
			try
			{
				_addIllegalStatus?.Invoke(local, new object[2] { "Injury", 1f });
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("[Bleeding] HurtEffect: " + ex.Message));
			}
		}

		internal Texture2D GetDropTexture()
		{
			if ((Object)(object)_dropTex == (Object)null)
			{
				_dropTex = LoadDropTexture();
			}
			return _dropTex;
		}

		private static Texture2D LoadDropTexture()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			try
			{
				string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "assets", "blood.png");
				if (File.Exists(path))
				{
					Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
					((Texture)val).filterMode = (FilterMode)1;
					if (ImageConversion.LoadImage(val, File.ReadAllBytes(path)))
					{
						return val;
					}
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("[Bleeding] LoadDropTexture: " + ex.Message));
			}
			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_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: 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.Clamp01(1f - (Mathf.Sqrt(num7 * num7 + num8 * num8) - num3 + 1.5f) / 1.5f);
					byte b = (num10 ? byte.MaxValue : (flag ? byte.MaxValue : ((byte)(num11 * 255f))));
					array[i * size + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, b);
				}
			}
			val.SetPixels32(array);
			val.Apply();
			return val;
		}

		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_004b: 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_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: 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 flag = (Object)(object)localInstance != (Object)null && localInstance.isBleeding;
			bool flag2 = flag || BleedingTracker.s_isFading;
			float fadeAlpha = BleedingTracker.FadeAlpha;
			float num = Mathf.Clamp01((cfgOverlayIntensity != null) ? cfgOverlayIntensity.Value : 1f);
			float num2 = _pulseTimer % 1f;
			float num3 = ((num2 < 0.2f) ? (num2 / 0.2f) : (1f - (num2 - 0.2f) / 0.8f));
			if (flag2 && num > 0.01f)
			{
				float num4 = BleedingTracker.s_level switch
				{
					BleedLevel.Light => 0.15f, 
					BleedLevel.Medium => 0.22f, 
					BleedLevel.Heavy => 0.32f, 
					BleedLevel.Massive => 0.45f, 
					_ => 0.2f, 
				} + (flag ? (num3 * 0.05f) : 0f);
				GUI.color = new Color(0.6f, 0f, 0f, num4 * num * fadeAlpha);
				GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)_guiTex);
			}
			if (_flashTimer > 0f && num > 0.01f)
			{
				GUI.color = new Color(0.55f, 0f, 0f, _flashTimer * 0.5f * num);
				GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)_guiTex);
			}
			if (flag2)
			{
				Texture2D dropTexture = GetDropTexture();
				if ((Object)(object)dropTexture != (Object)null)
				{
					GUI.color = new Color(0.75f, 0.06f, 0.06f, fadeAlpha);
					GUI.DrawTexture(new Rect((float)Screen.width - 112f, 16f, 96f, 96f), (Texture)(object)dropTexture);
				}
			}
			GUI.color = color;
		}
	}
	public enum BleedLevel
	{
		None,
		Light,
		Medium,
		Heavy,
		Massive
	}
	[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: " + ex.Message));
			}
		}
	}
	internal static class SpiderCheck
	{
		private const float WEB_THRESHOLD = 0.025f;

		public static bool IsGrabbedBySpider(Character c)
		{
			if ((Object)(object)c == (Object)null || c.refs == null || (Object)(object)c.refs.afflictions == (Object)null)
			{
				return false;
			}
			try
			{
				return c.refs.afflictions.GetCurrentStatus((STATUSTYPE)11) > 0.025f;
			}
			catch
			{
				return false;
			}
		}
	}
	public class TambiAfflictionOption : CustomOptionBase
	{
		private static readonly Dictionary<string, int> _values = new Dictionary<string, int>();

		public string modName;

		public string[] labels = new string[4] { "OFF", "LOW", "NORM", "HIGH" };

		public int defaultValue = 2;

		public Button button;

		public LocalizedText buttonText;

		public LocalizedText label;

		public Image buttonImage;

		public Color offColor;

		public Color defaultColor;

		public Color adjustedColor;

		public static int GetValue(string mod)
		{
			if (!_values.TryGetValue(mod, out var value))
			{
				return 2;
			}
			return value;
		}

		public static void SetValue(string mod, int value)
		{
			_values[mod] = value;
		}

		private void OnEnable()
		{
			if (!_values.ContainsKey(modName))
			{
				_values[modName] = defaultValue;
			}
			Refresh();
		}

		public override void OnClick()
		{
			((CustomOptionBase)this).OnClick();
			int value = GetValue(modName);
			value = (value + 1) % labels.Length;
			_values[modName] = value;
			Refresh();
		}

		public override void RestoreDefault()
		{
			_values[modName] = defaultValue;
			Refresh();
		}

		private void Refresh()
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			int value = GetValue(modName);
			if ((Object)(object)buttonText != (Object)null)
			{
				buttonText.autoSet = true;
				buttonText.SetIndex(labels[Mathf.Clamp(value, 0, labels.Length - 1)]);
			}
			if ((Object)(object)buttonImage != (Object)null)
			{
				((Graphic)buttonImage).color = ((value == defaultValue) ? defaultColor : adjustedColor);
			}
			if ((Object)(object)label != (Object)null)
			{
				label.SetText(modName);
			}
		}
	}
	[HarmonyPatch(typeof(CustomOptionsWindow), "Initialize")]
	internal static class TambiOptionInjector
	{
		private const string MOD_NAME = "Bleeding";

		private static bool _injected;

		[HarmonyPostfix]
		private static void Postfix(CustomOptionsWindow __instance)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Invalid comparison between Unknown and I4
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Expected O, but got Unknown
			if (_injected)
			{
				return;
			}
			try
			{
				CustomOptionMulti[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<CustomOptionMulti>(true);
				CustomOptionMulti val = null;
				CustomOptionMulti[] array = componentsInChildren;
				foreach (CustomOptionMulti val2 in array)
				{
					if ((int)val2.settingType == 300 || (int)val2.settingType == 400)
					{
						val = val2;
						break;
					}
				}
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				GameObject val3 = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)val).transform.parent);
				((Object)val3).name = "TambiOption_Bleeding";
				CustomOptionMulti component = val3.GetComponent<CustomOptionMulti>();
				if ((Object)(object)component == (Object)null)
				{
					Object.Destroy((Object)(object)val3);
					return;
				}
				Button button = component.button;
				LocalizedText buttonText = component.buttonText;
				LocalizedText label = component.label;
				Image buttonImage = component.buttonImage;
				Color offColor = component.offColor;
				Color defaultColor = component.defaultColor;
				Color adjustedColor = component.adjustedColor;
				string[] labels = component.labels;
				MonoBehaviour[] componentsInChildren2 = val3.GetComponentsInChildren<MonoBehaviour>(true);
				foreach (MonoBehaviour val4 in componentsInChildren2)
				{
					if (!((Object)(object)val4 == (Object)null))
					{
						if (val4 is EventTrigger)
						{
							Object.DestroyImmediate((Object)(object)val4);
						}
						else if (val4 is CustomOptionBase)
						{
							Object.DestroyImmediate((Object)(object)val4);
						}
						else if (val4 is CustomOptionTooltip)
						{
							Object.DestroyImmediate((Object)(object)val4);
						}
					}
				}
				TambiAfflictionOption tambiAfflictionOption = val3.AddComponent<TambiAfflictionOption>();
				tambiAfflictionOption.modName = "Bleeding";
				tambiAfflictionOption.button = button;
				tambiAfflictionOption.buttonText = buttonText;
				tambiAfflictionOption.label = label;
				tambiAfflictionOption.buttonImage = buttonImage;
				tambiAfflictionOption.offColor = offColor;
				tambiAfflictionOption.defaultColor = defaultColor;
				tambiAfflictionOption.adjustedColor = adjustedColor;
				tambiAfflictionOption.defaultValue = 2;
				if (labels != null && labels.Length != 0)
				{
					tambiAfflictionOption.labels = labels;
				}
				if ((Object)(object)button != (Object)null)
				{
					((UnityEventBase)button.onClick).RemoveAllListeners();
					((UnityEvent)button.onClick).AddListener(new UnityAction(((CustomOptionBase)tambiAfflictionOption).OnClick));
				}
				if ((Object)(object)label != (Object)null)
				{
					label.autoSet = false;
					label.index = "";
					label.SetText("Bleeding");
				}
				val3.SetActive(true);
				((Component)tambiAfflictionOption).SendMessage("Refresh", (SendMessageOptions)1);
				_injected = true;
				ManualLogSource logger = BleedingPlugin.Logger;
				if (logger != null)
				{
					logger.LogInfo((object)"[TambiOption] Bleeding option injected into Custom Expedition menu.");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger2 = BleedingPlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogWarning((object)("[TambiOption] Injection failed: " + ex.Message));
				}
			}
		}
	}
}