Decompiled source of Player Pain Sounds v1.0.4

BitWizrd.PlayerPainSounds.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BitWizrd.PlayerPainSounds.Configuration;
using FistVR;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Player Pain Sounds")]
[assembly: AssemblyDescription("Custom injury and death sounds for H3VR")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("BitWizrd")]
[assembly: AssemblyProduct("Player Pain Sounds")]
[assembly: AssemblyCopyright("Copyright © BitWizrd 2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("a1b2c3d4-e5f6-4a5b-8c7d-9e0f1a2b3c4d")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace BitWizrd.PlayerPainSounds
{
	public static class DamageCalculationHelper
	{
		public enum DamageType
		{
			Abstract,
			Projectile,
			Explosive,
			Melee,
			Environmental,
			Pistol,
			Shotgun,
			SMGRifle,
			Support,
			ExplosiveAmmo,
			MeleeWeapon,
			Trap,
			Blunt,
			Piercing,
			Cutting,
			Thermal,
			Chilling,
			EMP,
			Stunning,
			Blinding,
			Unknown
		}

		public enum BodyLocation
		{
			Head,
			Torso,
			Hand,
			Unknown
		}

		public struct DamageInfo
		{
			public float TotalDamage;

			public float KineticDamage;

			public float EnergeticDamage;

			public float BluntDamage;

			public float PiercingDamage;

			public float CuttingDamage;

			public float ThermalDamage;

			public float ChillingDamage;

			public float EMPDamage;

			public float StunningDamage;

			public float BlindingDamage;

			public float PointsDamage;

			public float StunDamage;

			public float MPa;

			public float MPaRootMeter;

			public Vector3 Force;

			public Vector2 UVCoords;

			public DamageType PrimaryType;

			public DamageType SecondaryType;

			public DamageClass SourceClass;

			public DamageType SourceDamageType;

			public BodyLocation Location;

			public PlayerHitBoxType HitboxType;

			public Vector3 ImpactPosition;

			public Vector3 HitNormal;

			public Vector3 StrikeDirection;

			public Vector3 EdgeNormal;

			public float DamageSize;

			public bool IsInitialContact;

			public bool IsInside;

			public bool IsMelee;

			public bool IsPlayer;

			public bool DoesIgnite;

			public bool DoesFreeze;

			public bool DoesDisrupt;

			public int SourceIFF;

			public Transform SourceTransform;

			public Vector3 SourcePoint;

			public Transform ShotOrigin;

			public FVRFireArm SourceFirearm;

			public bool WouldAffectHealth;

			public float HealthBefore;

			public float HealthAfter;

			public float HealthBeforeRaw;

			public float HealthAfterRaw;

			public float MaxHealth;

			public float DamagePercentage;

			public string SeverityCategory;

			public bool PlayerHasDamageResist;

			public bool PlayerHasDamageMultiplier;

			public float PlayerDamageResistValue;

			public float PlayerDamageMultiplier;

			public bool PlayerIsBlort;

			public bool PlayerIsDlort;

			public float EffectiveDamageAfterResist;
		}

		private const float MIN_EFFECTIVE_DAMAGE = 0.1f;

		private const float HEALTH_PRECISION_MULTIPLIER = 100f;

		private const float HIGH_DAMAGE_THRESHOLD = 0.5f;

		private const float LOW_DAMAGE_THRESHOLD = 0.1f;

		public static DamageInfo AnalyzeDamage(float damageAmount, FVRPlayerHitbox hitbox, Vector3 impactPosition)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			DamageInfo info = default(DamageInfo);
			info.TotalDamage = damageAmount;
			info.KineticDamage = damageAmount;
			info.EnergeticDamage = 0f;
			info.BluntDamage = damageAmount;
			info.PrimaryType = DamageType.Blunt;
			info.SourceClass = (DamageClass)0;
			info.SourceDamageType = (DamageType)0;
			info.HitboxType = hitbox.Type;
			info.Location = ConvertHitboxToBodyLocation(hitbox.Type);
			info.ImpactPosition = impactPosition;
			info.IsInitialContact = true;
			CalculatePlayerStateFactors(ref info);
			CalculateHealthImpact(ref info);
			info.SeverityCategory = CategorizeDamageSeverity(info.DamagePercentage);
			LogDamageAnalysis(info);
			return info;
		}

		public static DamageInfo AnalyzeDamage(Damage damageObj, FVRPlayerHitbox hitbox, Vector3 impactPosition)
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: 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_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			DamageInfo info = default(DamageInfo);
			info.BluntDamage = damageObj.Dam_Blunt;
			info.PiercingDamage = damageObj.Dam_Piercing;
			info.CuttingDamage = damageObj.Dam_Cutting;
			info.KineticDamage = damageObj.Dam_TotalKinetic;
			info.ThermalDamage = damageObj.Dam_Thermal;
			info.ChillingDamage = damageObj.Dam_Chilling;
			info.EMPDamage = damageObj.Dam_EMP;
			info.EnergeticDamage = damageObj.Dam_TotalEnergetic;
			info.StunningDamage = damageObj.Dam_Stunning;
			info.BlindingDamage = damageObj.Dam_Blinding;
			info.TotalDamage = info.KineticDamage + info.EnergeticDamage;
			info.SourceClass = damageObj.Class;
			info.PrimaryType = DeterminePrimaryDamageType(damageObj);
			info.SecondaryType = DetermineSecondaryDamageType(damageObj);
			info.HitboxType = hitbox.Type;
			info.Location = ConvertHitboxToBodyLocation(hitbox.Type);
			info.ImpactPosition = impactPosition;
			info.HitNormal = damageObj.hitNormal;
			info.StrikeDirection = damageObj.strikeDir;
			info.EdgeNormal = damageObj.edgeNormal;
			info.DamageSize = damageObj.damageSize;
			info.IsInitialContact = true;
			info.SourceIFF = damageObj.Source_IFF;
			info.SourceTransform = damageObj.Source_Transform;
			info.SourcePoint = damageObj.Source_Point;
			CalculatePlayerStateFactors(ref info);
			CalculateHealthImpact(ref info);
			info.SeverityCategory = CategorizeDamageSeverity(info.DamagePercentage);
			LogDamageAnalysis(info);
			return info;
		}

		public static DamageInfo AnalyzeDamage(DamageDealt damageDealt, FVRPlayerHitbox hitbox, Vector3 impactPosition)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: 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)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: 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)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: 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_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: 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_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			DamageInfo info = default(DamageInfo);
			info.PointsDamage = damageDealt.PointsDamage;
			info.StunDamage = damageDealt.StunDamage;
			info.MPa = damageDealt.MPa;
			info.MPaRootMeter = damageDealt.MPaRootMeter;
			info.Force = damageDealt.force;
			info.UVCoords = damageDealt.uvCoords;
			info.TotalDamage = damageDealt.PointsDamage;
			info.KineticDamage = damageDealt.PointsDamage;
			info.EnergeticDamage = 0f;
			info.SourceDamageType = damageDealt.Type;
			info.PrimaryType = ConvertDamageDealtTypeToDamageType(damageDealt.Type);
			if (damageDealt.IsMelee)
			{
				info.SecondaryType = DamageType.MeleeWeapon;
			}
			info.HitboxType = hitbox.Type;
			info.Location = ConvertHitboxToBodyLocation(hitbox.Type);
			info.ImpactPosition = impactPosition;
			info.HitNormal = damageDealt.hitNormal;
			info.StrikeDirection = damageDealt.strikeDir;
			info.IsInitialContact = damageDealt.IsInitialContact;
			info.IsInside = damageDealt.IsInside;
			info.IsMelee = damageDealt.IsMelee;
			info.IsPlayer = damageDealt.IsPlayer;
			info.DoesIgnite = damageDealt.DoesIgnite;
			info.DoesFreeze = damageDealt.DoesFreeze;
			info.DoesDisrupt = damageDealt.DoesDisrupt;
			info.ShotOrigin = damageDealt.ShotOrigin;
			info.SourceFirearm = damageDealt.SourceFirearm;
			CalculatePlayerStateFactors(ref info);
			CalculateHealthImpact(ref info);
			info.SeverityCategory = CategorizeDamageSeverity(info.DamagePercentage);
			LogDamageAnalysis(info);
			return info;
		}

		public static bool WouldDamageAffectHealth(float damageAmount)
		{
			if (damageAmount <= 0f)
			{
				return false;
			}
			if ((Object)(object)GM.CurrentPlayerBody == (Object)null)
			{
				return false;
			}
			float health = GM.CurrentPlayerBody.Health;
			float num = health - damageAmount;
			int num2 = (int)health;
			int num3 = (int)num;
			bool flag = num2 != num3;
			if (PlayerPainSoundsPlugin.configDebugMessages.Value)
			{
				PlayerPainSoundsPlugin.LogInfo($"H3VR Health Impact: damage={damageAmount}, rawHealth: {health:F4} -> {num:F4}, truncated: {num2} -> {num3}, affects={flag}");
			}
			return flag;
		}

		public static bool WouldDamageAffectHealth(DamageInfo damageInfo)
		{
			return WouldDamageAffectHealth((damageInfo.EffectiveDamageAfterResist > 0f) ? damageInfo.EffectiveDamageAfterResist : damageInfo.TotalDamage);
		}

		public static bool ShouldTriggerPainSound(DamageInfo damageInfo)
		{
			if (damageInfo.TotalDamage <= 0f)
			{
				return false;
			}
			if (!damageInfo.IsInitialContact)
			{
				return false;
			}
			if (!WouldPassH3VRHitboxThreshold(damageInfo))
			{
				return false;
			}
			if (!damageInfo.WouldAffectHealth)
			{
				return false;
			}
			return true;
		}

		private static bool WouldPassH3VRHitboxThreshold(DamageInfo damageInfo)
		{
			if ((Object)(object)GM.CurrentPlayerBody == (Object)null)
			{
				return false;
			}
			float num = damageInfo.TotalDamage;
			if (GM.CurrentPlayerBody.IsBlort && damageInfo.EnergeticDamage > 0f)
			{
				num = damageInfo.KineticDamage;
			}
			else if (GM.CurrentPlayerBody.IsDlort && damageInfo.EnergeticDamage > 0f)
			{
				num = damageInfo.KineticDamage + damageInfo.EnergeticDamage * 3f;
			}
			if (GM.CurrentPlayerBody.IsDamResist || GM.CurrentPlayerBody.IsDamMult)
			{
				float damageResist = GM.CurrentPlayerBody.GetDamageResist();
				if (damageResist <= 0.01f)
				{
					return false;
				}
				num *= damageResist;
			}
			bool flag = num > 0.1f;
			if (PlayerPainSoundsPlugin.configDebugMessages.Value)
			{
				PlayerPainSoundsPlugin.LogInfo($"H3VR Hitbox Threshold Check: original={damageInfo.TotalDamage}, processed={num}, passes={flag}");
			}
			return flag;
		}

		public static string GetSoundCategoryForDamage(DamageInfo damageInfo)
		{
			if (damageInfo.DamagePercentage >= 0.5f)
			{
				return "pain_high";
			}
			if (damageInfo.DamagePercentage <= 0.1f)
			{
				return "pain_low";
			}
			return "pain_default";
		}

		private static BodyLocation ConvertHitboxToBodyLocation(PlayerHitBoxType hitboxType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected I4, but got Unknown
			return (int)hitboxType switch
			{
				0 => BodyLocation.Head, 
				1 => BodyLocation.Torso, 
				2 => BodyLocation.Hand, 
				_ => BodyLocation.Unknown, 
			};
		}

		private static void CalculatePlayerStateFactors(ref DamageInfo info)
		{
			if (!((Object)(object)GM.CurrentPlayerBody == (Object)null))
			{
				info.PlayerHasDamageResist = GM.CurrentPlayerBody.IsDamResist || GM.CurrentPlayerBody.IsDamMult;
				info.PlayerHasDamageMultiplier = GM.CurrentPlayerBody.IsDamMult || GM.CurrentPlayerBody.isDamPowerUp;
				info.PlayerIsBlort = GM.CurrentPlayerBody.IsBlort;
				info.PlayerIsDlort = GM.CurrentPlayerBody.IsDlort;
				if (info.PlayerHasDamageResist)
				{
					info.PlayerDamageResistValue = GM.CurrentPlayerBody.GetDamageResist();
				}
				else
				{
					info.PlayerDamageResistValue = 1f;
				}
				if (info.PlayerHasDamageMultiplier)
				{
					info.PlayerDamageMultiplier = GM.CurrentPlayerBody.GetDamageMult();
				}
				else
				{
					info.PlayerDamageMultiplier = 1f;
				}
				float num = info.TotalDamage;
				if (info.PlayerIsBlort && info.EnergeticDamage > 0f)
				{
					num = info.KineticDamage;
				}
				else if (info.PlayerIsDlort && info.EnergeticDamage > 0f)
				{
					num = info.KineticDamage + info.EnergeticDamage * 3f;
				}
				num = ((!(info.PlayerDamageResistValue <= 0.01f)) ? (num * info.PlayerDamageResistValue) : 0f);
				info.EffectiveDamageAfterResist = num;
			}
		}

		private static void CalculateHealthImpact(ref DamageInfo info)
		{
			if ((Object)(object)GM.CurrentPlayerBody == (Object)null)
			{
				info.WouldAffectHealth = false;
				info.HealthBefore = 0f;
				info.HealthAfter = 0f;
				info.HealthBeforeRaw = 0f;
				info.HealthAfterRaw = 0f;
				info.MaxHealth = 0f;
				info.DamagePercentage = 0f;
				return;
			}
			float health = GM.CurrentPlayerBody.Health;
			float num = GM.CurrentPlayerBody.GetMaxHealthPlayerRaw();
			float num2 = ((info.EffectiveDamageAfterResist > 0f) ? info.EffectiveDamageAfterResist : info.TotalDamage);
			float num3 = health - num2;
			info.HealthBeforeRaw = health;
			info.HealthAfterRaw = num3;
			info.MaxHealth = num;
			info.HealthBefore = GM.CurrentPlayerBody.GetPlayerHealth();
			info.HealthAfter = num3 / num;
			if (num > 0f)
			{
				info.DamagePercentage = num2 / num;
			}
			else
			{
				info.DamagePercentage = 0f;
			}
			info.WouldAffectHealth = WouldDamageAffectHealth(info);
		}

		private static string CategorizeDamageSeverity(float damagePercentage)
		{
			if (damagePercentage >= 0.5f)
			{
				return "High";
			}
			if (damagePercentage <= 0.1f)
			{
				return "Low";
			}
			return "Medium";
		}

		private static DamageType DeterminePrimaryDamageType(Damage damageObj)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected I4, but got Unknown
			DamageClass @class = damageObj.Class;
			switch (@class - 1)
			{
			case 0:
				return DamageType.Projectile;
			case 1:
				return DamageType.Explosive;
			case 2:
				return DamageType.Melee;
			case 3:
				return DamageType.Environmental;
			default:
			{
				float num = 0f;
				DamageType result = DamageType.Unknown;
				if (damageObj.Dam_Blunt > num)
				{
					num = damageObj.Dam_Blunt;
					result = DamageType.Blunt;
				}
				if (damageObj.Dam_Piercing > num)
				{
					num = damageObj.Dam_Piercing;
					result = DamageType.Piercing;
				}
				if (damageObj.Dam_Cutting > num)
				{
					num = damageObj.Dam_Cutting;
					result = DamageType.Cutting;
				}
				if (damageObj.Dam_Thermal > num)
				{
					num = damageObj.Dam_Thermal;
					result = DamageType.Thermal;
				}
				if (damageObj.Dam_Chilling > num)
				{
					num = damageObj.Dam_Chilling;
					result = DamageType.Chilling;
				}
				if (damageObj.Dam_EMP > num)
				{
					num = damageObj.Dam_EMP;
					result = DamageType.EMP;
				}
				if (damageObj.Dam_Stunning > num)
				{
					num = damageObj.Dam_Stunning;
					result = DamageType.Stunning;
				}
				if (damageObj.Dam_Blinding > num)
				{
					num = damageObj.Dam_Blinding;
					result = DamageType.Blinding;
				}
				return result;
			}
			}
		}

		private static DamageType DetermineSecondaryDamageType(Damage damageObj)
		{
			float[] array = new float[8] { damageObj.Dam_Blunt, damageObj.Dam_Piercing, damageObj.Dam_Cutting, damageObj.Dam_Thermal, damageObj.Dam_Chilling, damageObj.Dam_EMP, damageObj.Dam_Stunning, damageObj.Dam_Blinding };
			DamageType[] array2 = new DamageType[8]
			{
				DamageType.Blunt,
				DamageType.Piercing,
				DamageType.Cutting,
				DamageType.Thermal,
				DamageType.Chilling,
				DamageType.EMP,
				DamageType.Stunning,
				DamageType.Blinding
			};
			float num = 0f;
			float num2 = 0f;
			int num3 = -1;
			int num4 = -1;
			for (int i = 0; i < array.Length; i++)
			{
				if (array[i] > num)
				{
					num2 = num;
					num4 = num3;
					num = array[i];
					num3 = i;
				}
				else if (array[i] > num2)
				{
					num2 = array[i];
					num4 = i;
				}
			}
			if (num4 < 0)
			{
				return DamageType.Unknown;
			}
			return array2[num4];
		}

		private static DamageType ConvertDamageDealtTypeToDamageType(DamageType sourceType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected I4, but got Unknown
			return (sourceType - 1) switch
			{
				0 => DamageType.Pistol, 
				1 => DamageType.Shotgun, 
				2 => DamageType.SMGRifle, 
				3 => DamageType.Support, 
				4 => DamageType.ExplosiveAmmo, 
				5 => DamageType.MeleeWeapon, 
				6 => DamageType.Trap, 
				_ => DamageType.Unknown, 
			};
		}

		private static void LogDamageAnalysis(DamageInfo info)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			if (PlayerPainSoundsPlugin.configDebugMessages.Value)
			{
				PlayerPainSoundsPlugin.LogInfo($"=== Damage Analysis ===");
				PlayerPainSoundsPlugin.LogInfo($"Total: {info.TotalDamage:F2} damage to {info.Location} ({info.HitboxType})");
				PlayerPainSoundsPlugin.LogInfo($"Breakdown - K:{info.KineticDamage:F2}, E:{info.EnergeticDamage:F2} | Blunt:{info.BluntDamage:F2}, Pierce:{info.PiercingDamage:F2}, Cut:{info.CuttingDamage:F2}");
				PlayerPainSoundsPlugin.LogInfo($"Energetic - Thermal:{info.ThermalDamage:F2}, Chill:{info.ChillingDamage:F2}, EMP:{info.EMPDamage:F2}");
				PlayerPainSoundsPlugin.LogInfo($"Special - Stun:{info.StunningDamage:F2}, Blind:{info.BlindingDamage:F2}");
				PlayerPainSoundsPlugin.LogInfo($"Type: {info.PrimaryType} / {info.SecondaryType} | Class: {info.SourceClass} | Source: {info.SourceDamageType}");
				PlayerPainSoundsPlugin.LogInfo($"Health: {info.HealthBeforeRaw:F0} -> {info.HealthAfterRaw:F0} ({info.DamagePercentage * 100f:F1}% of {info.MaxHealth:F0})");
				PlayerPainSoundsPlugin.LogInfo($"Player State - Resist:{info.PlayerDamageResistValue:F2}, Mult:{info.PlayerDamageMultiplier:F2}, Blort:{info.PlayerIsBlort}, Dlort:{info.PlayerIsDlort}");
				PlayerPainSoundsPlugin.LogInfo($"Effective Damage: {info.EffectiveDamageAfterResist:F2} | Affects Health: {info.WouldAffectHealth} | Category: {GetSoundCategoryForDamage(info)}");
				PlayerPainSoundsPlugin.LogInfo($"========================");
			}
		}

		public static float ApplyLocationMultiplier(float baseDamage, BodyLocation location, DamageInfo damageInfo)
		{
			switch (location)
			{
			case BodyLocation.Head:
				return baseDamage * 1f;
			case BodyLocation.Torso:
				return baseDamage * 1f;
			case BodyLocation.Hand:
				if ((Object)(object)damageInfo.SourceFirearm != (Object)null)
				{
					return 0f;
				}
				return baseDamage * 1f;
			default:
				return baseDamage;
			}
		}

		public static float CalculateDamageReduction(DamageInfo damageInfo)
		{
			return 0f;
		}

		public static DamageInfo ProcessEnvironmentalDamage(float damage, Vector3 position, DamageType environmentType)
		{
			//IL_001a: 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)
			DamageInfo result = default(DamageInfo);
			result.TotalDamage = damage;
			result.PrimaryType = environmentType;
			result.ImpactPosition = position;
			return result;
		}

		public static string GetImpactSoundCategory(Damage damage)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			if (damage == null)
			{
				return "impact_default";
			}
			if ((int)damage.Class == 1)
			{
				return "impact_bullet";
			}
			if ((int)damage.Class == 2)
			{
				return "impact_default";
			}
			if (damage.Dam_Cutting > 0f || damage.Dam_Piercing > 0f)
			{
				return "impact_default";
			}
			if (damage.Dam_Blunt > 0f)
			{
				return "impact_default";
			}
			_ = damage.Dam_Thermal;
			_ = 0f;
			return "impact_default";
		}

		public static string GetImpactSoundCategory(PlayerHitBoxType hitboxType, float damageAmount)
		{
			_ = 50f;
			return "impact_default";
		}
	}
	public class InjurySoundManager : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <>c__DisplayClass91_0
		{
			public string packName;

			internal bool <LoadSinglePackAndSwitch>b__0(OuchPackInfo p)
			{
				return p.Name == packName;
			}
		}

		[CompilerGenerated]
		private sealed class <LoadCustomSoundPacks>d__88 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public InjurySoundManager <>4__this;

			private List<OuchPackInfo>.Enumerator <>7__wrap1;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadCustomSoundPacks>d__88(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>7__wrap1 = default(List<OuchPackInfo>.Enumerator);
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				try
				{
					int num = <>1__state;
					InjurySoundManager injurySoundManager = <>4__this;
					switch (num)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<>7__wrap1 = PlayerPainSoundsPlugin.DiscoveredOuchPacks.GetEnumerator();
						<>1__state = -3;
						break;
					case 1:
						<>1__state = -3;
						break;
					}
					if (<>7__wrap1.MoveNext())
					{
						OuchPackInfo current = <>7__wrap1.Current;
						string name = current.Name;
						string path = current.Path;
						injurySoundManager.InitializePackDictionaries(name);
						injurySoundManager.injurySounds[name].Clear();
						injurySoundManager.deathSounds[name].Clear();
						injurySoundManager.availableCategories[name].Clear();
						<>2__current = ((MonoBehaviour)injurySoundManager).StartCoroutine(injurySoundManager.LoadSoundPackCategories(name, path));
						<>1__state = 1;
						return true;
					}
					<>m__Finally1();
					<>7__wrap1 = default(List<OuchPackInfo>.Enumerator);
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				((IDisposable)<>7__wrap1).Dispose();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <LoadSinglePackAndSwitch>d__91 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public string packName;

			public InjurySoundManager <>4__this;

			private <>c__DisplayClass91_0 <>8__1;

			private string <packPath>5__2;

			private Dictionary<string, List<AudioClip>> <packInjurySounds>5__3;

			private Dictionary<string, List<AudioClip>> <packDeathSounds>5__4;

			private Dictionary<string, List<AudioClip>> <packImpactSounds>5__5;

			private string[] <>7__wrap5;

			private int <>7__wrap6;

			private string <category>5__8;

			private List<AudioClip> <clips>5__9;

			private string[] <>7__wrap9;

			private int <>7__wrap10;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadSinglePackAndSwitch>d__91(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>8__1 = null;
				<packPath>5__2 = null;
				<packInjurySounds>5__3 = null;
				<packDeathSounds>5__4 = null;
				<packImpactSounds>5__5 = null;
				<>7__wrap5 = null;
				<category>5__8 = null;
				<clips>5__9 = null;
				<>7__wrap9 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				InjurySoundManager injurySoundManager = <>4__this;
				if (num != 0)
				{
					if (num != 1)
					{
						return false;
					}
					<>1__state = -1;
					<>7__wrap10++;
					goto IL_01ee;
				}
				<>1__state = -1;
				<>8__1 = new <>c__DisplayClass91_0();
				<>8__1.packName = packName;
				OuchPackInfo ouchPackInfo = PlayerPainSoundsPlugin.DiscoveredOuchPacks.FirstOrDefault((OuchPackInfo p) => p.Name == <>8__1.packName);
				if (ouchPackInfo == null)
				{
					PlayerPainSoundsPlugin.LogError("Pack not found: " + <>8__1.packName);
					injurySoundManager.currentSoundPack = "Default";
					injurySoundManager.ClearLoadedSounds();
					injurySoundManager.LoadDefaultSounds();
					PlayerPainSoundsPlugin.LogInfo("Fell back to Default sound pack");
					return false;
				}
				<packPath>5__2 = ouchPackInfo.Path;
				if (string.IsNullOrEmpty(<packPath>5__2) || !Directory.Exists(<packPath>5__2))
				{
					PlayerPainSoundsPlugin.LogError("Invalid pack path: " + <packPath>5__2);
					injurySoundManager.currentSoundPack = "Default";
					injurySoundManager.ClearLoadedSounds();
					injurySoundManager.LoadDefaultSounds();
					PlayerPainSoundsPlugin.LogInfo("Fell back to Default sound pack due to invalid path");
					return false;
				}
				PlayerPainSoundsPlugin.LogInfo("Loading sound pack from path: " + <packPath>5__2);
				<packInjurySounds>5__3 = new Dictionary<string, List<AudioClip>>();
				<packDeathSounds>5__4 = new Dictionary<string, List<AudioClip>>();
				<packImpactSounds>5__5 = new Dictionary<string, List<AudioClip>>();
				<>7__wrap5 = SoundCategories.ALL_CATEGORIES;
				<>7__wrap6 = 0;
				goto IL_032c;
				IL_0317:
				<category>5__8 = null;
				<>7__wrap6++;
				goto IL_032c;
				IL_032c:
				if (<>7__wrap6 < <>7__wrap5.Length)
				{
					<category>5__8 = <>7__wrap5[<>7__wrap6];
					string path = Path.Combine(<packPath>5__2, <category>5__8);
					if (Directory.Exists(path))
					{
						<clips>5__9 = new List<AudioClip>();
						string[] files = Directory.GetFiles(path, "*.*", SearchOption.TopDirectoryOnly);
						<>7__wrap9 = files;
						<>7__wrap10 = 0;
						goto IL_01ee;
					}
					goto IL_0317;
				}
				<>7__wrap5 = null;
				bool flag = false;
				injurySoundManager.InitializePackDictionaries(<>8__1.packName);
				if (<packInjurySounds>5__3.Count > 0)
				{
					injurySoundManager.injurySounds[<>8__1.packName] = <packInjurySounds>5__3;
					foreach (string key in <packInjurySounds>5__3.Keys)
					{
						injurySoundManager.availableCategories[<>8__1.packName].Add(key);
					}
					flag = true;
				}
				if (<packDeathSounds>5__4.Count > 0)
				{
					injurySoundManager.deathSounds[<>8__1.packName] = <packDeathSounds>5__4;
					foreach (string key2 in <packDeathSounds>5__4.Keys)
					{
						injurySoundManager.availableCategories[<>8__1.packName].Add(key2);
					}
					flag = true;
				}
				if (<packImpactSounds>5__5.Count > 0)
				{
					injurySoundManager.impactSounds[<>8__1.packName] = <packImpactSounds>5__5;
					foreach (string key3 in <packImpactSounds>5__5.Keys)
					{
						injurySoundManager.availableCategories[<>8__1.packName].Add(key3);
					}
					flag = true;
				}
				if (!flag)
				{
					PlayerPainSoundsPlugin.LogWarning("No sounds found in pack: " + <>8__1.packName);
					injurySoundManager.currentSoundPack = "Default";
					injurySoundManager.ClearLoadedSounds();
					injurySoundManager.LoadDefaultSounds();
					PlayerPainSoundsPlugin.LogInfo("Fell back to Default sound pack due to no sounds found");
				}
				else
				{
					injurySoundManager.currentSoundPack = <>8__1.packName;
					PlayerPainSoundsPlugin.LogInfo("Successfully loaded sound pack: " + <>8__1.packName);
				}
				if (injurySoundManager.hasInitialized && injurySoundManager.isInLastStand)
				{
					injurySoundManager.PlayerStateCheck();
				}
				return false;
				IL_01ee:
				if (<>7__wrap10 < <>7__wrap9.Length)
				{
					string file = <>7__wrap9[<>7__wrap10];
					<>2__current = ((MonoBehaviour)injurySoundManager).StartCoroutine(injurySoundManager.LoadSoundFile(file, <clips>5__9, <category>5__8));
					<>1__state = 1;
					return true;
				}
				<>7__wrap9 = null;
				if (<clips>5__9.Count > 0)
				{
					if (<category>5__8 == "death")
					{
						<packDeathSounds>5__4[<category>5__8] = <clips>5__9;
						PlayerPainSoundsPlugin.LogInfo("Loaded " + <clips>5__9.Count + " death sounds for category: " + <category>5__8);
					}
					else if (SoundCategories.IS_IMPACT_CATEGORY[<category>5__8])
					{
						<packImpactSounds>5__5[<category>5__8] = <clips>5__9;
						PlayerPainSoundsPlugin.LogInfo("Loaded " + <clips>5__9.Count + " impact sounds for category: " + <category>5__8);
					}
					else
					{
						<packInjurySounds>5__3[<category>5__8] = <clips>5__9;
						PlayerPainSoundsPlugin.LogInfo("Loaded " + <clips>5__9.Count + " injury sounds for category: " + <category>5__8);
					}
				}
				<clips>5__9 = null;
				goto IL_0317;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <LoadSoundFile>d__122 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public string file;

			public List<AudioClip> clips;

			public string category;

			private string <fileUrl>5__2;

			private WWW <www>5__3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadSoundFile>d__122(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<fileUrl>5__2 = null;
				<www>5__3 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_009f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a9: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					if (string.IsNullOrEmpty(file) || clips == null)
					{
						PlayerPainSoundsPlugin.LogError("Invalid parameters passed to LoadSoundFile");
						return false;
					}
					string text = Path.GetExtension(file).ToLower();
					if (ConfigurationConstants.IsSupportedAudioFormat(text))
					{
						<fileUrl>5__2 = "file:///" + file.Replace("\\", "/");
						PlayerPainSoundsPlugin.LogInfo("Loading sound file: " + <fileUrl>5__2);
						<www>5__3 = null;
						<www>5__3 = new WWW(<fileUrl>5__2);
						<>2__current = <www>5__3;
						<>1__state = 1;
						return true;
					}
					PlayerPainSoundsPlugin.LogWarning("Unsupported audio file format: " + text + " - File: " + file);
					break;
				}
				case 1:
					<>1__state = -1;
					try
					{
						if (!string.IsNullOrEmpty(<www>5__3.error))
						{
							PlayerPainSoundsPlugin.LogError("Error loading sound file: " + <fileUrl>5__2 + " - " + <www>5__3.error);
							return false;
						}
						AudioClip audioClip = WWWAudioExtensions.GetAudioClip(<www>5__3, false, false);
						if ((Object)(object)audioClip != (Object)null)
						{
							((Object)audioClip).name = Path.GetFileNameWithoutExtension(file);
							clips.Add(audioClip);
							PlayerPainSoundsPlugin.LogInfo("Successfully loaded sound: " + ((Object)audioClip).name + " for category: " + category);
						}
						else
						{
							PlayerPainSoundsPlugin.LogError("Failed to create AudioClip from: " + <fileUrl>5__2);
						}
					}
					catch (Exception ex)
					{
						PlayerPainSoundsPlugin.LogError("Exception in LoadSoundFile: " + ex.Message);
					}
					finally
					{
						if (<www>5__3 != null)
						{
							<www>5__3.Dispose();
						}
					}
					<fileUrl>5__2 = null;
					<www>5__3 = null;
					break;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <LoadSoundPackCategories>d__90 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public string packPath;

			public InjurySoundManager <>4__this;

			public string packName;

			private string[] <>7__wrap1;

			private int <>7__wrap2;

			private string <category>5__4;

			private bool <hasValidSounds>5__5;

			private string[] <>7__wrap5;

			private int <>7__wrap6;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadSoundPackCategories>d__90(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>7__wrap1 = null;
				<category>5__4 = null;
				<>7__wrap5 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				InjurySoundManager injurySoundManager = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>7__wrap1 = SoundCategories.ALL_CATEGORIES;
					<>7__wrap2 = 0;
					goto IL_0303;
				case 1:
					<>1__state = -1;
					goto IL_02a1;
				case 2:
					<>1__state = -1;
					goto IL_02a1;
				case 3:
					{
						<>1__state = -1;
						goto IL_02a1;
					}
					IL_0303:
					if (<>7__wrap2 < <>7__wrap1.Length)
					{
						<category>5__4 = <>7__wrap1[<>7__wrap2];
						string path = Path.Combine(packPath, <category>5__4);
						if (Directory.Exists(path))
						{
							string[] files = Directory.GetFiles(path, "*.*", SearchOption.TopDirectoryOnly);
							<hasValidSounds>5__5 = false;
							<>7__wrap5 = files;
							<>7__wrap6 = 0;
							goto IL_02af;
						}
						goto IL_02ee;
					}
					<>7__wrap1 = null;
					PlayerPainSoundsPlugin.LogInfo(string.Format("Loaded pack '{0}' with categories: {1}", packName, string.Join(", ", injurySoundManager.availableCategories[packName].ToArray())));
					return false;
					IL_02ee:
					<category>5__4 = null;
					<>7__wrap2++;
					goto IL_0303;
					IL_02a1:
					<>7__wrap6++;
					goto IL_02af;
					IL_02af:
					if (<>7__wrap6 < <>7__wrap5.Length)
					{
						string text = <>7__wrap5[<>7__wrap6];
						string text2 = Path.GetExtension(text).ToLower();
						if (text2 == ".wav" || text2 == ".ogg")
						{
							<hasValidSounds>5__5 = true;
							if (<category>5__4 == "death")
							{
								if (!injurySoundManager.deathSounds[packName].ContainsKey(<category>5__4))
								{
									injurySoundManager.deathSounds[packName][<category>5__4] = new List<AudioClip>();
								}
								<>2__current = ((MonoBehaviour)injurySoundManager).StartCoroutine(injurySoundManager.LoadSoundFile(text, injurySoundManager.deathSounds[packName][<category>5__4], <category>5__4));
								<>1__state = 1;
								return true;
							}
							if (SoundCategories.IS_IMPACT_CATEGORY[<category>5__4])
							{
								if (!injurySoundManager.impactSounds[packName].ContainsKey(<category>5__4))
								{
									injurySoundManager.impactSounds[packName][<category>5__4] = new List<AudioClip>();
								}
								<>2__current = ((MonoBehaviour)injurySoundManager).StartCoroutine(injurySoundManager.LoadSoundFile(text, injurySoundManager.impactSounds[packName][<category>5__4], <category>5__4));
								<>1__state = 2;
								return true;
							}
							if (!injurySoundManager.injurySounds[packName].ContainsKey(<category>5__4))
							{
								injurySoundManager.injurySounds[packName][<category>5__4] = new List<AudioClip>();
							}
							<>2__current = ((MonoBehaviour)injurySoundManager).StartCoroutine(injurySoundManager.LoadSoundFile(text, injurySoundManager.injurySounds[packName][<category>5__4], <category>5__4));
							<>1__state = 3;
							return true;
						}
						goto IL_02a1;
					}
					<>7__wrap5 = null;
					if (<hasValidSounds>5__5)
					{
						injurySoundManager.availableCategories[packName].Add(<category>5__4);
					}
					goto IL_02ee;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <PlayCriticalHealthSoundWithDelay>d__79 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public InjurySoundManager <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <PlayCriticalHealthSoundWithDelay>d__79(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Expected O, but got Unknown
				int num = <>1__state;
				InjurySoundManager injurySoundManager = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(0.5f);
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					if (!injurySoundManager.isCriticalHealthEnabled || (Object)(object)injurySoundManager.audioSource == (Object)null || injurySoundManager.isDying)
					{
						return false;
					}
					AudioClip val = null;
					if (injurySoundManager.currentSoundPack == "Default")
					{
						val = injurySoundManager.GetDefaultCriticalHealthSound();
					}
					else if (injurySoundManager.injurySounds.ContainsKey(injurySoundManager.currentSoundPack) && injurySoundManager.injurySounds[injurySoundManager.currentSoundPack].ContainsKey("critical_health") && injurySoundManager.injurySounds[injurySoundManager.currentSoundPack]["critical_health"].Count > 0)
					{
						List<AudioClip> sounds = injurySoundManager.injurySounds[injurySoundManager.currentSoundPack]["critical_health"];
						val = injurySoundManager.GetUniqueRandomSound("critical_health", sounds);
					}
					if ((Object)(object)val == (Object)null)
					{
						PlayerPainSoundsPlugin.LogInfo("No critical health sound available");
						return false;
					}
					float num2 = 1f * injurySoundManager.GetVolumeMultiplier();
					injurySoundManager.audioSource2D.pitch = 1f;
					injurySoundManager.audioSource2D.PlayOneShot(val, num2);
					PlayerPainSoundsPlugin.LogInfo("Playing critical health sound");
					return false;
				}
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <PlayInjuryClipsWithDelay>d__111 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public float delay;

			public InjurySoundManager <>4__this;

			public Vector3 headPosition;

			public float pitch;

			public AudioClip clip;

			public float spatialVolume;

			public float volume2D;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <PlayInjuryClipsWithDelay>d__111(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0058: Unknown result type (might be due to invalid IL or missing references)
				//IL_00df: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Expected O, but got Unknown
				int num = <>1__state;
				InjurySoundManager injurySoundManager = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (delay > 0f)
					{
						<>2__current = (object)new WaitForSeconds(delay);
						<>1__state = 1;
						return true;
					}
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				((Component)injurySoundManager.audioSource).transform.position = headPosition;
				injurySoundManager.audioSource.pitch = pitch;
				injurySoundManager.audioSource2D.pitch = pitch;
				injurySoundManager.audioSource.PlayOneShot(clip, spatialVolume);
				injurySoundManager.audioSource2D.PlayOneShot(clip, volume2D);
				injurySoundManager.lastInjurySoundTime = Time.time;
				injurySoundManager.lastPlayedInjuryClip = clip;
				string text = delay.ToString();
				Vector3 val = headPosition;
				PlayerPainSoundsPlugin.LogInfo("Playing injury sound with delay " + text + " seconds at head position: " + ((object)(Vector3)(ref val)).ToString());
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <PlayPainAndDeathSequence>d__116 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public InjurySoundManager <>4__this;

			public AudioClip deathSound;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <PlayPainAndDeathSequence>d__116(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_002b: 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_005d: Unknown result type (might be due to invalid IL or missing references)
				//IL_009e: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00be: Expected O, but got Unknown
				//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
				//IL_0108: Unknown result type (might be due to invalid IL or missing references)
				//IL_0153: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				InjurySoundManager injurySoundManager = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					Vector3 position = GM.CurrentPlayerBody.Head.position;
					AudioClip appropriateSound = injurySoundManager.GetAppropriateSound();
					if ((Object)(object)appropriateSound != (Object)null)
					{
						float num2 = 1f * injurySoundManager.GetVolumeMultiplier();
						((Component)injurySoundManager.audioSource).transform.position = position;
						injurySoundManager.audioSource.spatialBlend = 1f;
						float num3 = num2 * 0.2f;
						injurySoundManager.audioSource.PlayOneShot(appropriateSound, num3);
						injurySoundManager.audioSource2D.PlayOneShot(appropriateSound, num2);
						PlayerPainSoundsPlugin.LogInfo($"Playing pain sound before death at head position: {position}");
						<>2__current = (object)new WaitForSeconds(0.1f);
						<>1__state = 1;
						return true;
					}
					break;
				}
				case 1:
					<>1__state = -1;
					break;
				}
				if ((Object)(object)deathSound != (Object)null)
				{
					Vector3 position = GM.CurrentPlayerBody.Head.position;
					float num4 = 1f * injurySoundManager.GetVolumeMultiplier();
					((Component)injurySoundManager.audioSource).transform.position = position;
					injurySoundManager.audioSource.spatialBlend = 1f;
					float num5 = num4 * 0.2f;
					injurySoundManager.audioSource.PlayOneShot(deathSound, num5);
					injurySoundManager.audioSource2D.PlayOneShot(deathSound, num4);
					PlayerPainSoundsPlugin.LogInfo($"Playing death sound after pain at head position: {position}");
					((MonoBehaviour)injurySoundManager).StartCoroutine(injurySoundManager.ResetStateAfterDeathSound());
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <ResetStateAfterDeathSound>d__121 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public InjurySoundManager <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ResetStateAfterDeathSound>d__121(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Expected O, but got Unknown
				int num = <>1__state;
				InjurySoundManager injurySoundManager = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(5f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					injurySoundManager.isDying = false;
					injurySoundManager.m_hasPlayedDeathSound = false;
					if (PlayerPainSoundsPlugin.IsManagerReady())
					{
						injurySoundManager.PlayerStateCheck();
					}
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <StartLoadingSoundPacks>d__83 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public InjurySoundManager <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <StartLoadingSoundPacks>d__83(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				InjurySoundManager injurySoundManager = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					injurySoundManager.isLoading = true;
					injurySoundManager.LoadDefaultSounds();
					<>2__current = ((MonoBehaviour)injurySoundManager).StartCoroutine(injurySoundManager.LoadCustomSoundPacks());
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					string value = PlayerPainSoundsPlugin.configInjurySoundPack.Value;
					injurySoundManager.SetSoundPack(value);
					injurySoundManager.isLoading = false;
					return false;
				}
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <TransitionLastStandSound>d__87 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public InjurySoundManager <>4__this;

			public string newPackName;

			private bool <wasInLastStand>5__2;

			private bool <shouldBeInLastStand>5__3;

			private float <startVolume>5__4;

			private float <fadeStartTime>5__5;

			private float <fadeDuration>5__6;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <TransitionLastStandSound>d__87(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0286: Unknown result type (might be due to invalid IL or missing references)
				//IL_0290: Expected O, but got Unknown
				int num = <>1__state;
				InjurySoundManager injurySoundManager = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					injurySoundManager.isTransitioningPacks = true;
					<wasInLastStand>5__2 = injurySoundManager.isInLastStand;
					PlayerPainSoundsPlugin.LogInfo("Starting transition to sound pack: " + newPackName + " (was in last stand: " + <wasInLastStand>5__2 + ")");
					float num2 = GM.CurrentPlayerBody.GetPlayerHealthRaw();
					float num3 = GM.CurrentPlayerBody.GetMaxHealthPlayerRaw();
					float num4 = num2 / num3;
					<shouldBeInLastStand>5__3 = num4 <= injurySoundManager.lastStandThreshold && injurySoundManager.isLastStandEnabled;
					if (<wasInLastStand>5__2 && (Object)(object)injurySoundManager.lastStandAudioSource != (Object)null && injurySoundManager.lastStandAudioSource.isPlaying)
					{
						<startVolume>5__4 = injurySoundManager.lastStandAudioSource.volume;
						<fadeStartTime>5__5 = Time.time;
						<fadeDuration>5__6 = 0.5f;
						PlayerPainSoundsPlugin.LogInfo("Fading out last stand sound");
						goto IL_0159;
					}
					goto IL_0184;
				}
				case 1:
					<>1__state = -1;
					goto IL_0159;
				case 2:
					<>1__state = -1;
					PlayerPainSoundsPlugin.LogInfo("Finished loading sounds for pack: " + newPackName);
					goto IL_026a;
				case 3:
					{
						<>1__state = -1;
						injurySoundManager.StartLastStandSound();
						PlayerPainSoundsPlugin.LogInfo("Restarted last stand with new sound pack");
						break;
					}
					IL_0184:
					if (newPackName == "Default")
					{
						injurySoundManager.currentSoundPack = "Default";
						injurySoundManager.ClearLoadedSounds();
						injurySoundManager.LoadDefaultSounds();
						PlayerPainSoundsPlugin.LogInfo("Transitioned to Default sound pack");
					}
					else
					{
						if (!injurySoundManager.injurySounds.ContainsKey(newPackName) || !injurySoundManager.deathSounds.ContainsKey(newPackName) || !injurySoundManager.availableCategories.ContainsKey(newPackName))
						{
							PlayerPainSoundsPlugin.LogInfo("Loading sounds for pack: " + newPackName);
							<>2__current = ((MonoBehaviour)injurySoundManager).StartCoroutine(injurySoundManager.LoadSinglePackAndSwitch(newPackName));
							<>1__state = 2;
							return true;
						}
						injurySoundManager.currentSoundPack = newPackName;
						PlayerPainSoundsPlugin.LogInfo("Transitioned to sound pack: " + newPackName);
					}
					goto IL_026a;
					IL_0159:
					if (Time.time < <fadeStartTime>5__5 + <fadeDuration>5__6)
					{
						float num5 = (Time.time - <fadeStartTime>5__5) / <fadeDuration>5__6;
						injurySoundManager.lastStandAudioSource.volume = Mathf.Lerp(<startVolume>5__4, 0f, num5);
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					injurySoundManager.lastStandAudioSource.Stop();
					injurySoundManager.lastStandAudioSource.clip = null;
					goto IL_0184;
					IL_026a:
					if (<wasInLastStand>5__2 & <shouldBeInLastStand>5__3)
					{
						injurySoundManager.isInLastStand = true;
						<>2__current = (object)new WaitForSeconds(0.1f);
						<>1__state = 3;
						return true;
					}
					break;
				}
				injurySoundManager.isTransitioningPacks = false;
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static InjurySoundManager _instance;

		private Dictionary<string, Dictionary<string, List<AudioClip>>> injurySounds = new Dictionary<string, Dictionary<string, List<AudioClip>>>();

		private Dictionary<string, Dictionary<string, List<AudioClip>>> deathSounds = new Dictionary<string, Dictionary<string, List<AudioClip>>>();

		private Dictionary<string, Dictionary<string, List<AudioClip>>> impactSounds = new Dictionary<string, Dictionary<string, List<AudioClip>>>();

		private Dictionary<string, HashSet<string>> availableCategories = new Dictionary<string, HashSet<string>>();

		private string currentSoundPack = "Default";

		private bool isDying;

		private const float DEATH_SOUND_VOLUME = 1f;

		private const float MIN_PITCH_VARIANCE = 0.98f;

		private const float MAX_PITCH_VARIANCE = 1.02f;

		private const float CRITICAL_HEALTH_DELAY = 0.5f;

		private const float PAIN_DEATH_DELAY = 0.1f;

		private AudioSource lastStandAudioSource;

		private bool isInLastStand;

		private bool isLastStandEnabled = true;

		private float lastStandThreshold = 0.25f;

		private const float FADE_DURATION = 2f;

		private float fadeStartTime;

		private float targetVolume = 1f;

		private bool isFadingIn;

		private bool isFadingOut;

		private bool shouldBeInLastStand;

		private bool hasCriticalHealthTriggered;

		private bool isCriticalHealthEnabled = true;

		private float criticalHealthThreshold = 0.25f;

		private const float HIGH_DAMAGE_THRESHOLD = 0.5f;

		private const float LOW_DAMAGE_THRESHOLD = 0.1f;

		private bool playPainWithDeath;

		private bool enableImpactSounds = true;

		private float impactVolumeMultiplier = 1f;

		private float lastImpactSoundTime;

		private const float MIN_TIME_BETWEEN_IMPACTS = 0.05f;

		private AudioSource audioSource;

		private AudioSource audioSource2D;

		private AudioSource impactAudioSource;

		private float lastInjurySoundTime;

		private const float MIN_TIME_BETWEEN_SOUNDS = 0.1f;

		private AudioClip lastPlayedInjuryClip;

		private bool hasInitialized;

		private bool isTransitioningPacks;

		public bool m_hasPlayedDeathSound;

		private Dictionary<string, AudioClip> lastPlayedClips = new Dictionary<string, AudioClip>();

		private bool enablePainSounds = true;

		private bool preventPainOverlap;

		public static InjurySoundManager Instance
		{
			get
			{
				return _instance;
			}
			set
			{
				_instance = value;
			}
		}

		public bool isLoading { get; private set; }

		public string CurrentSoundPack => currentSoundPack;

		public bool IsDying
		{
			get
			{
				return isDying;
			}
			set
			{
				isDying = value;
			}
		}

		public float LastStandThreshold => lastStandThreshold;

		public float CriticalHealthThreshold => criticalHealthThreshold;

		public void SetVolumeMultiplier(float multiplier)
		{
			PlayerPainSoundsPlugin.configVolumeMultiplier.Value = Mathf.Clamp(multiplier, 0f, 2f);
		}

		private float GetVolumeMultiplier()
		{
			return PlayerPainSoundsPlugin.configVolumeMultiplier.Value;
		}

		public void SetLastStandEnabled(bool enabled)
		{
			isLastStandEnabled = enabled;
			if (!enabled && isInLastStand)
			{
				StopLastStandSound();
			}
			PlayerStateCheck();
		}

		public void SetLastStandThreshold(float threshold)
		{
			lastStandThreshold = Mathf.Clamp01(threshold);
			PlayerStateCheck();
		}

		public void SetCriticalHealthEnabled(bool enabled)
		{
			isCriticalHealthEnabled = enabled;
			if (!enabled)
			{
				hasCriticalHealthTriggered = false;
			}
			PlayerStateCheck();
		}

		public void SetCriticalHealthThreshold(float threshold)
		{
			criticalHealthThreshold = Mathf.Clamp01(threshold);
			hasCriticalHealthTriggered = false;
			PlayerStateCheck();
		}

		public void SetPlayPainWithDeath(bool enabled)
		{
			playPainWithDeath = enabled;
			PlayerPainSoundsPlugin.LogInfo("Play pain with death set to: " + enabled);
		}

		public void SetEnableImpactSounds(bool enabled)
		{
			enableImpactSounds = enabled;
			PlayerPainSoundsPlugin.LogInfo("Impact sounds enabled: " + enabled);
		}

		public void SetImpactVolumeMultiplier(float multiplier)
		{
			impactVolumeMultiplier = Mathf.Clamp(multiplier, 0f, 5f);
			PlayerPainSoundsPlugin.LogInfo("Impact volume multiplier set to: " + multiplier);
		}

		public void SetEnablePainSounds(bool enabled)
		{
			enablePainSounds = enabled;
			PlayerPainSoundsPlugin.LogInfo("Pain sounds enabled: " + enabled);
		}

		public void SetPreventPainOverlap(bool enabled)
		{
			preventPainOverlap = enabled;
			PlayerPainSoundsPlugin.LogInfo("Prevent pain overlap enabled: " + enabled);
		}

		private float GetImpactVolumeMultiplier()
		{
			return impactVolumeMultiplier;
		}

		private void Awake()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
				Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
				audioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
				audioSource.spatialBlend = 1f;
				audioSource.minDistance = 0.1f;
				audioSource.maxDistance = 15f;
				audioSource.rolloffMode = (AudioRolloffMode)0;
				audioSource2D = ((Component)this).gameObject.AddComponent<AudioSource>();
				audioSource2D.spatialBlend = 0f;
				audioSource2D.volume = 1f;
				audioSource2D.priority = 0;
				audioSource.priority = 128;
				lastStandAudioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
				lastStandAudioSource.spatialBlend = 0f;
				lastStandAudioSource.minDistance = 1f;
				lastStandAudioSource.maxDistance = 15f;
				lastStandAudioSource.rolloffMode = (AudioRolloffMode)1;
				lastStandAudioSource.loop = true;
				lastStandAudioSource.playOnAwake = false;
				impactAudioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
				impactAudioSource.spatialBlend = 1f;
				impactAudioSource.minDistance = 0.1f;
				impactAudioSource.maxDistance = 25f;
				impactAudioSource.rolloffMode = (AudioRolloffMode)1;
				impactAudioSource.priority = 64;
			}
			else
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}

		private void Update()
		{
			if ((Object)(object)lastStandAudioSource != (Object)null && lastStandAudioSource.isPlaying)
			{
				UpdateFadeState();
			}
		}

		private void UpdateFadeState()
		{
			if (isFadingIn)
			{
				float num = Mathf.Clamp01((Time.time - fadeStartTime) / 2f);
				lastStandAudioSource.volume = Mathf.Lerp(0f, targetVolume, num);
				if (num >= 1f)
				{
					isFadingIn = false;
				}
			}
			else if (isFadingOut)
			{
				float num2 = Mathf.Clamp01((Time.time - fadeStartTime) / 2f);
				lastStandAudioSource.volume = Mathf.Lerp(targetVolume, 0f, num2);
				if (num2 >= 1f)
				{
					lastStandAudioSource.Stop();
					isFadingOut = false;
					isInLastStand = false;
				}
			}
		}

		private void StartFadeIn(AudioSource source, float targetVol, float duration)
		{
			source.volume = 0f;
			targetVolume = targetVol * GetVolumeMultiplier();
			fadeStartTime = Time.time;
			isFadingIn = true;
			isFadingOut = false;
		}

		private void StartFadeOut(AudioSource source, float duration)
		{
			targetVolume = source.volume;
			fadeStartTime = Time.time;
			isFadingOut = true;
			isFadingIn = false;
		}

		public void PlayerStateCheck()
		{
			if ((Object)(object)GM.CurrentPlayerBody == (Object)null || !hasInitialized)
			{
				hasInitialized = true;
			}
			else
			{
				if (PlayerPainSoundsPlugin.IsPlayerDead())
				{
					return;
				}
				float num = GM.CurrentPlayerBody.GetPlayerHealthRaw();
				float num2 = GM.CurrentPlayerBody.GetMaxHealthPlayerRaw();
				if (num2 <= 0f)
				{
					return;
				}
				float num3 = num / num2;
				CheckCriticalHealthState(num3);
				if (!isLastStandEnabled)
				{
					if (isInLastStand)
					{
						isInLastStand = false;
						StopLastStandSound();
					}
					return;
				}
				shouldBeInLastStand = num3 <= lastStandThreshold && !isDying;
				if (shouldBeInLastStand && !isInLastStand && !lastStandAudioSource.isPlaying)
				{
					isInLastStand = true;
					StartLastStandSound();
				}
				else if (!shouldBeInLastStand && isInLastStand)
				{
					isInLastStand = false;
					StopLastStandSound();
				}
			}
		}

		private void CheckCriticalHealthState(float healthPercent)
		{
			if (isCriticalHealthEnabled)
			{
				bool flag = healthPercent <= criticalHealthThreshold;
				if (flag && !hasCriticalHealthTriggered && !isDying)
				{
					((MonoBehaviour)this).StartCoroutine(PlayCriticalHealthSoundWithDelay());
					hasCriticalHealthTriggered = true;
				}
				else if (!flag && hasCriticalHealthTriggered)
				{
					hasCriticalHealthTriggered = false;
				}
			}
		}

		private IEnumerator PlayCriticalHealthSoundWithDelay()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <PlayCriticalHealthSoundWithDelay>d__79(0)
			{
				<>4__this = this
			};
		}

		private AudioClip GetDefaultCriticalHealthSound()
		{
			return Resources.Load<AudioClip>("Sounds/Default/critical_health");
		}

		private void StartLastStandSound()
		{
			if (isLastStandEnabled && !((Object)(object)lastStandAudioSource == (Object)null) && !lastStandAudioSource.isPlaying)
			{
				AudioClip val = null;
				if (currentSoundPack == "Default")
				{
					val = GetDefaultLastStandSound();
				}
				else if (injurySounds.ContainsKey(currentSoundPack) && injurySounds[currentSoundPack].ContainsKey("last_stand") && injurySounds[currentSoundPack]["last_stand"].Count > 0)
				{
					List<AudioClip> sounds = injurySounds[currentSoundPack]["last_stand"];
					val = GetUniqueRandomSound("last_stand", sounds);
				}
				if ((Object)(object)val == (Object)null)
				{
					isInLastStand = false;
					return;
				}
				lastStandAudioSource.clip = val;
				StartFadeIn(lastStandAudioSource, 1f, 2f);
				lastStandAudioSource.Play();
			}
		}

		private void StopLastStandSound()
		{
			if ((Object)(object)lastStandAudioSource != (Object)null && lastStandAudioSource.isPlaying)
			{
				StartFadeOut(lastStandAudioSource, 2f);
			}
		}

		public IEnumerator StartLoadingSoundPacks()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <StartLoadingSoundPacks>d__83(0)
			{
				<>4__this = this
			};
		}

		public void StopAllSounds()
		{
			if ((Object)(object)audioSource != (Object)null)
			{
				audioSource.Stop();
				audioSource.clip = null;
			}
			if ((Object)(object)audioSource2D != (Object)null)
			{
				audioSource2D.Stop();
				audioSource2D.clip = null;
			}
			if ((Object)(object)impactAudioSource != (Object)null)
			{
				impactAudioSource.Stop();
				impactAudioSource.clip = null;
			}
			if ((Object)(object)lastStandAudioSource != (Object)null)
			{
				lastStandAudioSource.Stop();
				lastStandAudioSource.clip = null;
				isFadingIn = false;
				isFadingOut = false;
			}
			lastPlayedInjuryClip = null;
			lastInjurySoundTime = 0f;
			lastImpactSoundTime = 0f;
		}

		public void SetSoundPack(string packName)
		{
			if (!string.IsNullOrEmpty(packName) && !(packName == currentSoundPack))
			{
				PlayerPainSoundsPlugin.LogInfo("Switching sound pack from '" + currentSoundPack + "' to '" + packName + "'");
				if ((Object)(object)audioSource != (Object)null)
				{
					audioSource.Stop();
				}
				if ((Object)(object)audioSource2D != (Object)null)
				{
					audioSource2D.Stop();
				}
				if ((Object)(object)lastStandAudioSource != (Object)null && lastStandAudioSource.isPlaying)
				{
					((MonoBehaviour)this).StartCoroutine(TransitionLastStandSound(packName));
				}
				else
				{
					SwitchSoundPackDirect(packName);
				}
			}
		}

		private void SwitchSoundPackDirect(string packName)
		{
			if (packName == "Default")
			{
				currentSoundPack = "Default";
				ClearLoadedSounds();
				LoadDefaultSounds();
				PlayerPainSoundsPlugin.LogInfo("Switched to Default sound pack");
				PlayerStateCheck();
			}
			else if (!injurySounds.ContainsKey(packName) || !deathSounds.ContainsKey(packName) || !availableCategories.ContainsKey(packName))
			{
				PlayerPainSoundsPlugin.LogInfo("Loading sounds for pack: " + packName);
				((MonoBehaviour)this).StartCoroutine(LoadSinglePackAndSwitch(packName));
			}
			else
			{
				currentSoundPack = packName;
				PlayerPainSoundsPlugin.LogInfo("Switched to sound pack: " + packName);
				PlayerStateCheck();
			}
		}

		private IEnumerator TransitionLastStandSound(string newPackName)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <TransitionLastStandSound>d__87(0)
			{
				<>4__this = this,
				newPackName = newPackName
			};
		}

		private IEnumerator LoadCustomSoundPacks()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadCustomSoundPacks>d__88(0)
			{
				<>4__this = this
			};
		}

		private void InitializePackDictionaries(string packName)
		{
			if (!injurySounds.ContainsKey(packName))
			{
				injurySounds[packName] = new Dictionary<string, List<AudioClip>>();
			}
			if (!deathSounds.ContainsKey(packName))
			{
				deathSounds[packName] = new Dictionary<string, List<AudioClip>>();
			}
			if (!impactSounds.ContainsKey(packName))
			{
				impactSounds[packName] = new Dictionary<string, List<AudioClip>>();
			}
			if (!availableCategories.ContainsKey(packName))
			{
				availableCategories[packName] = new HashSet<string>();
			}
		}

		private IEnumerator LoadSoundPackCategories(string packName, string packPath)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadSoundPackCategories>d__90(0)
			{
				<>4__this = this,
				packName = packName,
				packPath = packPath
			};
		}

		private IEnumerator LoadSinglePackAndSwitch(string packName)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadSinglePackAndSwitch>d__91(0)
			{
				<>4__this = this,
				packName = packName
			};
		}

		private void LoadDefaultSounds()
		{
			LoadDefaultInjurySounds();
			LoadDefaultDeathSounds();
			LoadDefaultLastStandSound();
		}

		private void LoadDefaultInjurySounds()
		{
			if (!injurySounds.ContainsKey("Default"))
			{
				injurySounds["Default"] = new Dictionary<string, List<AudioClip>>();
			}
			string[] aLL_CATEGORIES = SoundCategories.ALL_CATEGORIES;
			foreach (string key in aLL_CATEGORIES)
			{
				if (SoundCategories.IS_INJURY_CATEGORY[key] && !injurySounds["Default"].ContainsKey(key))
				{
					injurySounds["Default"][key] = new List<AudioClip>();
				}
			}
		}

		private void LoadDefaultDeathSounds()
		{
			if (!deathSounds.ContainsKey("Default"))
			{
				deathSounds["Default"] = new Dictionary<string, List<AudioClip>>();
			}
			if (!deathSounds["Default"].ContainsKey("death"))
			{
				deathSounds["Default"]["death"] = new List<AudioClip>();
			}
		}

		private void LoadDefaultLastStandSound()
		{
			if (!injurySounds.ContainsKey("Default"))
			{
				injurySounds["Default"] = new Dictionary<string, List<AudioClip>>();
			}
			if (!injurySounds["Default"].ContainsKey("last_stand"))
			{
				injurySounds["Default"]["last_stand"] = new List<AudioClip>();
			}
			if (!injurySounds["Default"].ContainsKey("critical_health"))
			{
				injurySounds["Default"]["critical_health"] = new List<AudioClip>();
			}
		}

		private void ClearLoadedSounds()
		{
			foreach (string item in injurySounds.Keys.ToList())
			{
				injurySounds[item].Clear();
			}
			foreach (string item2 in deathSounds.Keys.ToList())
			{
				deathSounds[item2].Clear();
			}
			foreach (string item3 in impactSounds.Keys.ToList())
			{
				impactSounds[item3].Clear();
			}
			availableCategories.Clear();
			if (lastPlayedClips != null)
			{
				lastPlayedClips.Clear();
			}
		}

		public bool HasSoundsInCategory(string packName, string category)
		{
			if (injurySounds.ContainsKey(packName) && injurySounds[packName].ContainsKey(category))
			{
				return injurySounds[packName][category].Count > 0;
			}
			return false;
		}

		public bool HasDeathSoundsInCategory(string packName, string category)
		{
			if (deathSounds.ContainsKey(packName) && deathSounds[packName].ContainsKey(category))
			{
				return deathSounds[packName][category].Count > 0;
			}
			return false;
		}

		public void PlayInjurySound(Vector3 position)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if (enablePainSounds && injurySounds.ContainsKey(currentSoundPack) && !((Object)(object)GM.CurrentPlayerBody == (Object)null) && !((float)GM.CurrentPlayerBody.GetPlayerHealthRaw() <= 0f) && !PlayerPainSoundsPlugin.IsPlayerDead() && !isDying)
			{
				PlayInjurySoundInternal(position, 1f, (PlayerHitBoxType)1, null);
			}
		}

		public void PlayInjurySound(Vector3 position, float distanceMult)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if (enablePainSounds && injurySounds.ContainsKey(currentSoundPack) && !((Object)(object)GM.CurrentPlayerBody == (Object)null) && !((float)GM.CurrentPlayerBody.GetPlayerHealthRaw() <= 0f) && !PlayerPainSoundsPlugin.IsPlayerDead() && !isDying)
			{
				PlayInjurySoundInternal(position, distanceMult, (PlayerHitBoxType)1, null);
			}
		}

		public void PlayInjurySound(Vector3 position, float distanceMult, PlayerHitBoxType hitboxType)
		{
			//IL_004e: 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)
			if (enablePainSounds && injurySounds.ContainsKey(currentSoundPack) && !((Object)(object)GM.CurrentPlayerBody == (Object)null) && !((float)GM.CurrentPlayerBody.GetPlayerHealthRaw() <= 0f) && !PlayerPainSoundsPlugin.IsPlayerDead() && !isDying)
			{
				PlayInjurySoundInternal(position, distanceMult, hitboxType, null);
			}
		}

		public void PlayInjurySound(Vector3 position, float distanceMult, PlayerHitBoxType hitboxType, Damage damage)
		{
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			if (!enablePainSounds || isTransitioningPacks || !hasInitialized || currentSoundPack == "Default")
			{
				return;
			}
			if ((Object)(object)GM.CurrentPlayerBody == (Object)null)
			{
				PlayerPainSoundsPlugin.LogInfo("Pain blocked - CurrentPlayerBody is null");
				return;
			}
			float num = GM.CurrentPlayerBody.GetPlayerHealthRaw();
			if (num <= 0f)
			{
				PlayerPainSoundsPlugin.LogInfo("Pain blocked - player health is " + num + " (dead)");
				return;
			}
			if (PlayerPainSoundsPlugin.IsPlayerDead() || isDying)
			{
				PlayerPainSoundsPlugin.LogInfo("Pain blocked - player dead or dying");
				return;
			}
			if (damage == null)
			{
				if (PlayerPainSoundsPlugin.configDebugMessages.Value)
				{
					PlayerPainSoundsPlugin.LogInfo("PlayInjurySound called with null damage - pain sound blocked");
				}
				return;
			}
			float num2 = damage.Dam_TotalKinetic + damage.Dam_TotalEnergetic;
			if (num2 <= 0f)
			{
				if (PlayerPainSoundsPlugin.configDebugMessages.Value)
				{
					PlayerPainSoundsPlugin.LogInfo($"PlayInjurySound called with zero damage ({num2}) - pain sound blocked");
				}
			}
			else if (!playPainWithDeath && num - num2 <= 0f)
			{
				PlayerPainSoundsPlugin.LogInfo("Pain blocked - damage would be lethal and play pain with death is disabled");
			}
			else
			{
				PlayInjurySoundInternalWithDamage(position, distanceMult, hitboxType, null, num2);
			}
		}

		public void PlayInjurySoundWithDamage(Vector3 position, float distanceMult, PlayerHitBoxType hitboxType, float damageAmount)
		{
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			if (!enablePainSounds || isTransitioningPacks || !hasInitialized || currentSoundPack == "Default")
			{
				return;
			}
			if ((Object)(object)GM.CurrentPlayerBody == (Object)null)
			{
				PlayerPainSoundsPlugin.LogInfo("Pain blocked - CurrentPlayerBody is null");
				return;
			}
			float num = GM.CurrentPlayerBody.GetPlayerHealthRaw();
			if (num <= 0f)
			{
				PlayerPainSoundsPlugin.LogInfo("Pain blocked - player health is " + num + " (dead)");
			}
			else if (PlayerPainSoundsPlugin.IsPlayerDead() || isDying)
			{
				PlayerPainSoundsPlugin.LogInfo("Pain blocked - player dead or dying");
			}
			else if (damageAmount <= 0f)
			{
				if (PlayerPainSoundsPlugin.configDebugMessages.Value)
				{
					PlayerPainSoundsPlugin.LogInfo($"PlayInjurySoundWithDamage called with zero damage ({damageAmount}) - pain sound blocked");
				}
			}
			else if (!playPainWithDeath && num - damageAmount <= 0f)
			{
				PlayerPainSoundsPlugin.LogInfo("Pain blocked - damage would be lethal and play pain with death is disabled");
			}
			else
			{
				PlayInjurySoundInternalWithDamage(position, distanceMult, hitboxType, null, damageAmount);
			}
		}

		public void OnPlayerHitDetected(PlayerHitBoxType hitboxType, float damageAmount, Vector3 position)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			if (PlayerPainSoundsPlugin.configDebugMessages.Value)
			{
				PlayerPainSoundsPlugin.LogInfo($"Hit detected on {hitboxType}: damage={damageAmount}, position={position}");
			}
		}

		public void PlayImpactSound(Vector3 position, Damage damage)
		{
			//IL_0063: 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)
			if (enableImpactSounds && damage != null && !(Time.time - lastImpactSoundTime < 0.05f))
			{
				string impactSoundCategory = DamageCalculationHelper.GetImpactSoundCategory(damage);
				string actualCategory;
				AudioClip impactSoundAndCategory = GetImpactSoundAndCategory(impactSoundCategory, out actualCategory);
				if ((Object)(object)impactSoundAndCategory != (Object)null)
				{
					float num = 1f * GetImpactVolumeMultiplier();
					float pitch = Random.Range(0.98f, 1.02f);
					((Component)impactAudioSource).transform.position = position;
					impactAudioSource.pitch = pitch;
					impactAudioSource.PlayOneShot(impactSoundAndCategory, num);
					lastImpactSoundTime = Time.time;
					PlayerPainSoundsPlugin.LogInfo($"Playing impact sound: {actualCategory} at {position}");
				}
			}
		}

		public void PlayImpactSoundWithType(Vector3 position, PlayerHitBoxType hitboxType, float damageAmount)
		{
			//IL_001d: 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_0092: Unknown result type (might be due to invalid IL or missing references)
			if (enableImpactSounds && !(Time.time - lastImpactSoundTime < 0.05f))
			{
				string impactSoundCategory = DamageCalculationHelper.GetImpactSoundCategory(hitboxType, damageAmount);
				string actualCategory;
				AudioClip impactSoundAndCategory = GetImpactSoundAndCategory(impactSoundCategory, out actualCategory);
				if ((Object)(object)impactSoundAndCategory != (Object)null)
				{
					float num = 1f * GetImpactVolumeMultiplier();
					float pitch = Random.Range(0.98f, 1.02f);
					((Component)impactAudioSource).transform.position = position;
					impactAudioSource.pitch = pitch;
					impactAudioSource.PlayOneShot(impactSoundAndCategory, num);
					lastImpactSoundTime = Time.time;
					PlayerPainSoundsPlugin.LogInfo($"Playing impact sound: {actualCategory} at {position}");
				}
			}
		}

		private AudioClip GetImpactSound(string category)
		{
			string actualCategory;
			return GetImpactSoundAndCategory(category, out actualCategory);
		}

		private AudioClip GetImpactSoundAndCategory(string category, out string actualCategory)
		{
			actualCategory = category;
			if (!impactSounds.ContainsKey(currentSoundPack))
			{
				PlayerPainSoundsPlugin.LogInfo("No impact sounds loaded for current sound pack: " + currentSoundPack);
				return null;
			}
			if (impactSounds[currentSoundPack].ContainsKey(category) && impactSounds[currentSoundPack][category].Count > 0)
			{
				List<AudioClip> list = impactSounds[currentSoundPack][category];
				int index = Random.Range(0, list.Count);
				PlayerPainSoundsPlugin.LogInfo($"Using impact category: {category} ({list.Count} sounds available)");
				return list[index];
			}
			if (category != "impact_default")
			{
				PlayerPainSoundsPlugin.LogInfo(string.Format("Impact category {0} not found, falling back to {1}", category, "impact_default"));
				actualCategory = "impact_default";
				return GetImpactSoundAndCategory("impact_default", out actualCategory);
			}
			if (impactSounds[currentSoundPack].Count > 0)
			{
				string arg = string.Join(", ", impactSounds[currentSoundPack].Keys.ToArray());
				PlayerPainSoundsPlugin.LogInfo($"Impact category {category} not found. Available impact categories: {arg}");
			}
			else
			{
				PlayerPainSoundsPlugin.LogInfo("No impact sounds available in current sound pack");
			}
			return null;
		}

		private void PlayInjurySoundInternal(Vector3 position, float distanceMult, PlayerHitBoxType hitboxType, AudioClip forcedClip)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			PlayInjurySoundInternalWithDamage(position, distanceMult, hitboxType, forcedClip, 0f);
		}

		private void PlayInjurySoundInternalWithDamage(Vector3 position, float distanceMult, PlayerHitBoxType hitboxType, AudioClip forcedClip, float damageAmount)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: 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)
			try
			{
				if (!enablePainSounds)
				{
					return;
				}
				if (preventPainOverlap && (audioSource.isPlaying || audioSource2D.isPlaying))
				{
					PlayerPainSoundsPlugin.LogInfo("Pain sound blocked due to overlap prevention - previous sound still playing");
					return;
				}
				if (Time.time - lastInjurySoundTime < 0.1f)
				{
					PlayerPainSoundsPlugin.LogInfo("Pain sound rate limited - too soon after last sound");
					return;
				}
				Vector3 position2 = ((Component)GM.CurrentPlayerBody.Head).transform.position;
				if (isTransitioningPacks || !hasInitialized || currentSoundPack == "Default" || Time.time - lastInjurySoundTime < 0.1f)
				{
					return;
				}
				if (!injurySounds.ContainsKey(currentSoundPack))
				{
					PlayerPainSoundsPlugin.LogWarning("No injury sounds found for current sound pack: " + currentSoundPack);
					return;
				}
				AudioClip val = forcedClip;
				if ((Object)(object)val == (Object)null)
				{
					if ((Object)(object)GM.CurrentPlayerBody == (Object)null)
					{
						return;
					}
					val = ((!(damageAmount > 0f)) ? GetAppropriateSound() : GetAppropriateSoundForDamage(damageAmount));
				}
				if (!((Object)(object)val != (Object)null))
				{
					return;
				}
				float num = 1f * distanceMult * GetVolumeMultiplier();
				float pitch = Random.Range(0.98f, 1.02f);
				float num2 = 0f;
				if (enableImpactSounds)
				{
					float num3 = Time.time - lastImpactSoundTime;
					num2 = 0.25f - num3;
					if (num2 < 0f)
					{
						num2 = 0f;
					}
				}
				float spatialVolume = num * 0.2f;
				lastInjurySoundTime = Time.time;
				((MonoBehaviour)this).StartCoroutine(PlayInjuryClipsWithDelay(val, spatialVolume, num, pitch, position2, num2));
			}
			catch (Exception ex)
			{
				PlayerPainSoundsPlugin.LogError("Error in PlayInjurySoundInternalWithDamage: " + ex.Message);
			}
		}

		private IEnumerator PlayInjuryClipsWithDelay(AudioClip clip, float spatialVolume, float volume2D, float pitch, Vector3 headPosition, float delay)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <PlayInjuryClipsWithDelay>d__111(0)
			{
				<>4__this = this,
				clip = clip,
				spatialVolume = spatialVolume,
				volume2D = volume2D,
				pitch = pitch,
				headPosition = headPosition,
				delay = delay
			};
		}

		private AudioClip GetAppropriateSound()
		{
			float num = GM.CurrentPlayerBody.GetPlayerHealthRaw();
			float num2 = GM.CurrentPlayerBody.GetMaxHealthPlayerRaw();
			if (num2 <= 0f)
			{
				return null;
			}
			float num3 = num / num2;
			string text = "pain_default";
			List<AudioClip> list = null;
			if (num3 <= 0.5f && injurySounds[currentSoundPack].ContainsKey("pain_high"))
			{
				list = injurySounds[currentSoundPack]["pain_high"];
				if (list != null && list.Count > 0)
				{
					text = "pain_high";
				}
			}
			if (list == null || list.Count == 0)
			{
				text = "pain_default";
				if (injurySounds[currentSoundPack].ContainsKey("pain_default") && injurySounds[currentSoundPack]["pain_default"].Count > 0)
				{
					list = injurySounds[currentSoundPack]["pain_default"];
				}
			}
			if ((list == null || list.Count == 0) && injurySounds[currentSoundPack].ContainsKey("pain_low"))
			{
				list = injurySounds[currentSoundPack]["pain_low"];
				if (list != null && list.Count > 0)
				{
					text = "pain_low";
				}
			}
			if (list == null || list.Count == 0)
			{
				text = "pain_default";
				if (injurySounds[currentSoundPack].ContainsKey("pain_default") && injurySounds[currentSoundPack]["pain_default"].Count > 0)
				{
					list = injurySounds[currentSoundPack]["pain_default"];
				}
			}
			if (list != null && list.Count > 0)
			{
				AudioClip uniqueRandomSound = GetUniqueRandomSound(text, list);
				PlayerPainSoundsPlugin.LogInfo("Selected sound from category: " + text + " (health-based fallback)");
				return uniqueRandomSound;
			}
			return null;
		}

		private AudioClip GetAppropriateSoundForDamage(float damageAmount)
		{
			float num = GM.CurrentPlayerBody.GetMaxHealthPlayerRaw();
			if (num <= 0f || damageAmount <= 0f)
			{
				return null;
			}
			DamageCalculationHelper.DamageInfo damageInfo = default(DamageCalculationHelper.DamageInfo);
			damageInfo.TotalDamage = damageAmount;
			damageInfo.DamagePercentage = damageAmount / num;
			string text = DamageCalculationHelper.GetSoundCategoryForDamage(damageInfo);
			List<AudioClip> list = null;
			if (injurySounds[currentSoundPack].ContainsKey(text) && injurySounds[currentSoundPack][text].Count > 0)
			{
				list = injurySounds[currentSoundPack][text];
			}
			if (list == null || list.Count == 0)
			{
				text = "pain_default";
				if (injurySounds[currentSoundPack].ContainsKey("pain_default") && injurySounds[currentSoundPack]["pain_default"].Count > 0)
				{
					list = injurySounds[currentSoundPack]["pain_default"];
				}
			}
			if (list == null || list.Count == 0)
			{
				if (injurySounds[currentSoundPack].ContainsKey("pain_high") && injurySounds[currentSoundPack]["pain_high"].Count > 0)
				{
					list = injurySounds[currentSoundPack]["pain_high"];
					text = "pain_high";
				}
				else if (injurySounds[currentSoundPack].ContainsKey("pain_low") && injurySounds[currentSoundPack]["pain_low"].Count > 0)
				{
					list = injurySounds[currentSoundPack]["pain_low"];
					text = "pain_low";
				}
			}
			if (list != null && list.Count > 0)
			{
				AudioClip uniqueRandomSound = GetUniqueRandomSound(text, list);
				PlayerPainSoundsPlugin.LogInfo($"Selected sound from category: {text} (damage={damageAmount:F2}, damagePercent={damageInfo.DamagePercentage * 100f:F1}%)");
				return uniqueRandomSound;
			}
			return null;
		}

		private AudioClip GetUniqueRandomSound(string category, List<AudioClip> sounds)
		{
			if (sounds == null || sounds.Count == 0)
			{
				return null;
			}
			if (sounds.Count == 1)
			{
				return sounds[0];
			}
			AudioClip val = null;
			if (lastPlayedClips.ContainsKey(category))
			{
				val = lastPlayedClips[category];
			}
			List<AudioClip> list = sounds;
			if ((Object)(object)val != (Object)null)
			{
				List<AudioClip> list2 = new List<AudioClip>();
				foreach (AudioClip sound in sounds)
				{
					if ((Object)(object)sound != (Object)(object)val)
					{
						list2.Add(sound);
					}
				}
				if (list2.Count > 0)
				{
					list = list2;
				}
			}
			AudioClip val2 = list[Random.Range(0, list.Count)];
			lastPlayedClips[category] = val2;
			return val2;
		}

		public void PlayDeathSound()
		{
			//IL_013a: 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_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)audioSource == (Object)null || currentSoundPack == "Default")
			{
				return;
			}
			try
			{
				if (m_hasPlayedDeathSound)
				{
					PlayerPainSoundsPlugin.LogInfo("Death sound already played, ignoring duplicate call");
					return;
				}
				m_hasPlayedDeathSound = true;
				isDying = true;
				StopLastStandSound();
				PlayerPainSoundsPlugin.LogInfo("Playing death sound (flag set to prevent duplicates)");
				if (!deathSounds.ContainsKey(currentSoundPack))
				{
					PlayerPainSoundsPlugin.LogWarning("No death sounds dictionary found for pack: " + currentSoundPack);
					return;
				}
				if (!deathSounds[currentSoundPack].ContainsKey("death"))
				{
					PlayerPainSoundsPlugin.LogWarning("No death sounds category found for pack: " + currentSoundPack);
					return;
				}
				List<AudioClip> list = deathSounds[currentSoundPack]["death"];
				if (list == null || list.Count == 0)
				{
					PlayerPainSoundsPlugin.LogInfo("No death sounds available in death category for pack: " + currentSoundPack);
					return;
				}
				AudioClip uniqueRandomSound = GetUniqueRandomSound("death", list);
				if (playPainWithDeath)
				{
					((MonoBehaviour)this).StartCoroutine(PlayPainAndDeathSequence(uniqueRandomSound));
				}
				else if ((Object)(object)uniqueRandomSound != (Object)null)
				{
					Vector3 position = GM.CurrentPlayerBody.Head.position;
					float num = 1f * GetVolumeMultiplier();
					((Component)audioSource).transform.position = position;
					audioSource.spatialBlend = 1f;
					float num2 = num * 0.2f;
					audioSource.PlayOneShot(uniqueRandomSound, num2);
					audioSource2D.PlayOneShot(uniqueRandomSound, num);
					PlayerPainSoundsPlugin.LogInfo($"Playing death sound at head position: {position}");
					((MonoBehaviour)this).StartCoroutine(ResetStateAfterDeathSound());
				}
			}
			catch (Exception ex)
			{
				PlayerPainSoundsPlugin.LogError("Error in PlayDeathSound: " + ex.Message);
			}
		}

		private IEnumerator PlayPainAndDeathSequence(AudioClip deathSound)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <PlayPainAndDeathSequence>d__116(0)
			{
				<>4__this = this,
				deathSound = deathSound
			};
		}

		public void ResetDyingState()
		{
			isDying = false;
			m_hasPlayedDeathSound = false;
			hasCriticalHealthTriggered = false;
			StopAllSounds();
		}

		private AudioClip GetDefaultLastStandSound()
		{
			return Resources.Load<AudioClip>("Sounds/Default/last_stand");
		}

		public AudioClip GetRandomSound(string category)
		{
			if (injurySounds.ContainsKey(currentSoundPack) && injurySounds[currentSoundPack].ContainsKey(category) && injurySounds[currentSoundPack][category].Count > 0)
			{
				List<AudioClip> list = injurySounds[currentSoundPack][category];
				return list[Random.Range(0, list.Count)];
			}
			return null;
		}

		public void PlaySoundAtPosition(AudioClip clip, Vector3 position, float distanceMult)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)audioSource == (Object)null)
			{
				PlayerPainSoundsPlugin.LogError("AudioSource is null when trying to play sound");
				return;
			}
			if ((Object)(object)clip == (Object)null)
			{
				PlayerPainSoundsPlugin.LogError("AudioClip is null when trying to play sound");
				return;
			}
			if (audioSource.spatialBlend != 1f)
			{
				audioSource.spatialBlend = 1f;
				PlayerPainSoundsPlugin.LogWarning("Reset audio source spatial blend to 3D");
			}
			if (audioSource.isPlaying)
			{
				audioSource.Stop();
			}
			Vector3 position2 = GM.CurrentPlayerBody.Head.position;
			((Component)audioSource).transform.position = position2;
			audioSource.volume = 1f * distanceMult * GetVolumeMultiplier();
			audioSource.pitch = Random.Range(0.98f, 1.02f);
			audioSource.clip = clip;
			audioSource.Play();
			string[] obj = new string[10]
			{
				"Playing sound: ",
				((Object)clip).name,
				" at head position ",
				null,
				null,
				null,
				null,
				null,
				null,
				null
			};
			Vector3 val = position2;
			obj[3] = ((object)(Vector3)(ref val)).ToString();
			obj[4] = " with volume ";
			obj[5] = audioSource.volume.ToString();
			obj[6] = " and spatial blend ";
			obj[7] = audioSource.spatialBlend.ToString();
			obj[8] = " and priority ";
			obj[9] = audioSource.priority.ToString();
			PlayerPainSoundsPlugin.LogInfo(string.Concat(obj));
		}

		private IEnumerator ResetStateAfterDeathSound()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ResetStateAfterDeathSound>d__121(0)
			{
				<>4__this = this
			};
		}

		private IEnumerator LoadSoundFile(string file, List<AudioClip> clips, string category)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadSoundFile>d__122(0)
			{
				file = file,
				clips = clips,
				category = category
			};
		}
	}
	public static class PlayerDeathPatches
	{
		[HarmonyPatch(typeof(FVRPlayerBody))]
		public class PlayerBodyDeathPatches
		{
			[HarmonyPostfix]
			[HarmonyPatch("RegisterPlayerHit", new Type[]
			{
				typeof(float),
				typeof(bool),
				typeof(int)
			})]
			private static void RegisterPlayerHitPostfix(FVRPlayerBody __instance, float DamagePoints, bool FromSelf, int iff, bool __result)
			{
				try
				{
					if (PlayerPainSoundsPlugin.IsManagerReady() && !((Object)(object)InjurySoundManager.Instance == (Object)null) && !((Object)(object)GM.CurrentPlayerBody == (Object)null) && __result && !InjurySoundManager.Instance.m_hasPlayedDeathSound)
					{
						PlayerPainSoundsPlugin.LogInfo("Player death confirmed via RegisterPlayerHit return value");
						InjurySoundManager.Instance.IsDying = true;
						if (InjurySoundManager.Instance.CurrentSoundPack != "Default")
						{
							InjurySoundManager.Instance.PlayDeathSound();
							return;
						}
						InjurySoundManager.Instance.m_hasPlayedDeathSound = true;
						PlayerPainSoundsPlugin.LogInfo("Death detected but using Default pack - not playing custom death sound");
					}
				}
				catch (Exception ex)
				{
					PlayerPainSoundsPlugin.LogError("Error in RegisterPlayerHit death detection: " + ex.Message);
				}
			}

			[HarmonyPostfix]
			[HarmonyPatch("HarmPercent")]
			private static void HarmPercentPostfix(FVRPlayerBody __instance, float f)
			{
				try
				{
					if (!PlayerPainSoundsPlugin.IsManagerReady() || (Object)(object)InjurySoundManager.Instance == (Object)null || (Object)(object)GM.CurrentPlayerBody == (Object)null)
					{
						return;
					}
					float num = __instance.GetPlayerHealthRaw();
					if (num <= 0f && !InjurySoundManager.Instance.m_hasPlayedDeathSound)
					{
						PlayerPainSoundsPlugin.LogInfo("Player death detected via HarmPercent - health: " + num);
						InjurySoundManager.Instance.IsDying = true;
						if (InjurySoundManager.Instance.CurrentSoundPack != "Default")
						{
							InjurySoundManager.Instance.PlayDeathSound();
							return;
						}
						InjurySoundManager.Instance.m_hasPlayedDeathSound = true;
						PlayerPainSoundsPlugin.LogInfo("Death detected via HarmPercent but using Default pack");
					}
				}
				catch (Exception ex)
				{
					PlayerPainSoundsPlugin.LogError("Error in HarmPercent death detection: " + ex.Message);
				}
			}
		}

		[HarmonyPatch(typeof(MG_Narrator))]
		public class NarratorPatches
		{
			[HarmonyPostfix]
			[HarmonyPatch("PlayDiedCheating")]
			private static void PlayDiedCheatingPostfix()
			{
				try
				{
					if (PlayerPainSoundsPlugin.IsManagerReady() && !((Object)(object)InjurySoundManager.Instance == (Object)null) && !((Object)(object)GM.CurrentPlayerBody == (Object)null) && !InjurySoundManager.Instance.m_hasPlayedDeathSound)
					{
						PlayerPainSoundsPlugin.LogInfo("Player death confirmed via PlayDiedCheating");
						InjurySoundManager.Instance.IsDying = true;
						if (InjurySoundManager.Instance.CurrentSoundPack != "Default")
						{
							InjurySoundManager.Instance.PlayDeathSound();
							return;
						}
						InjurySoundManager.Instance.m_hasPlayedDeathSound = true;
						PlayerPainSoundsPlugin.LogInfo("Death confirmed via PlayDiedCheating but using Default pack");
					}
				}
				catch (Exception ex)
				{
					PlayerPainSoundsPlugin.LogError("Error in PlayDiedCheating death detection: " + ex.Message);
				}
			}

			[HarmonyPostfix]
			[HarmonyPatch("PlayDiedOutOfHealth")]
			private static void PlayDiedOutOfHealthPostfix()
			{
				try
				{
					if (PlayerPainSoundsPlugin.IsManagerReady() && !((Object)(object)InjurySoundManager.Instance == (Object)null) && !((Object)(object)GM.CurrentPlayerBody == (Object)null) && !InjurySoundManager.Instance.m_hasPlayedDeathSound)
					{
						PlayerPainSoundsPlugin.LogInfo("Player death confirmed via PlayDiedOutOfHealth");
						InjurySoundManager.Instance.IsDying = true;
						if (InjurySoundManager.Instance.CurrentSoundPack != "Default")
						{
							InjurySoundManager.Instance.PlayDeathSound();
							return;
						}
						InjurySoundManager.Instance.m_hasPlayedDeathSound = true;
						PlayerPainSoundsPlugin.LogInfo("Death confirmed via PlayDiedOutOfHealth but using Default pack");
					}
				}
				catch (Exception ex)
				{
					PlayerPainSoundsPlugin.LogError("Error in PlayDiedOutOfHealth death detection: " + ex.Message);
				}
			}
		}

		[HarmonyPatch(typeof(GM))]
		[HarmonyPriority(600)]
		public class GMDeathPatches
		{
			[HarmonyPostfix]
			[HarmonyPatch("KillPlayer", new Type[]
			{
				typeof(bool),
				typeof(int)
			})]
			private static void KillPlayerPostfix(bool KilledSelf, int iff)
			{
				try
				{
					if (PlayerPainSoundsPlugin.IsManagerReady() && !((Object)(object)InjurySoundManager.Instance == (Object)null) && !InjurySoundManager.Instance.m_hasPlayedDeathSound)
					{
						PlayerPainSoundsPlugin.LogInfo("Player death confirmed via GM.KillPlayer");
						InjurySoundManager.Instance.IsDying = true;
						if (InjurySoundManager.Instance.CurrentSoundPack != "Default")
						{
							InjurySoundManager.Instance.PlayDeathSound();
							return;
						}
						InjurySoundManager.Instance.m_hasPlayedDeathSound = true;
						PlayerPainSoundsPlugin.LogInfo("Death confirmed via GM.KillPlayer but using Default pack");
					}
				}
				catch (Exception ex)
				{
					PlayerPainSoundsPlugin.LogError("Error in GM.KillPlayer death detection: " + ex.Message);
				}
			}
		}

		[HarmonyPatch(typeof(FVRSceneSettings))]
		public class SceneSet