Decompiled source of BetterHeals v2.0.1

BetterHeals.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BetterHeals.Config;
using BetterHeals.Patches;
using HarmonyLib;
using Photon.Pun;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("TeamHeals")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TeamHeals")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("8b363090-6f7a-451a-92a9-ed78838c26e0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace BetterHeals
{
	[BepInPlugin("MrBytesized.REPO.BetterHeals", "Better Heals", "2.1.0")]
	public class TeamHealsPlugin : BaseUnityPlugin
	{
		private const string mod_guid = "MrBytesized.REPO.BetterHeals";

		private const string mod_name = "Better Heals";

		private const string mod_version = "2.1.0";

		private readonly Harmony harmony = new Harmony("MrBytesized.REPO.BetterHeals");

		private static TeamHealsPlugin instance;

		internal static ManualLogSource Log;

		internal static readonly FieldRef<ItemHealthPack, ItemToggle> item_toggle_ref = AccessTools.FieldRefAccess<ItemHealthPack, ItemToggle>("itemToggle");

		internal static readonly FieldRef<ItemToggle, int> player_photon_id_ref = AccessTools.FieldRefAccess<ItemToggle, int>("playerTogglePhotonID");

		internal static readonly FieldRef<PlayerHealth, int> health_ref = AccessTools.FieldRefAccess<PlayerHealth, int>("health");

		internal static readonly FieldRef<PlayerHealth, int> max_health_ref = AccessTools.FieldRefAccess<PlayerHealth, int>("maxHealth");

		private (ConfigEntry<bool> configEntry, Action enablePatch, Action disablePatch, string description)[] patchArray;

		private void Awake()
		{
			if ((Object)(object)instance == (Object)null)
			{
				instance = this;
			}
			Configuration.Init(((BaseUnityPlugin)this).Config);
			Log = Logger.CreateLogSource("MrBytesized.REPO.BetterHeals");
			Log.LogInfo((object)"Team Heals mod has been activated");
			harmony.PatchAll(typeof(TeamHealsPlugin));
			harmony.PatchAll(typeof(PunManagerPatch));
			Log.LogInfo((object)"PunManager patch applied.");
			harmony.PatchAll(typeof(ItemHealthPackPatch));
			Log.LogInfo((object)"ItemHealthPack patch applied.");
			patchArray = new(ConfigEntry<bool>, Action, Action, string)[5]
			{
				(Configuration.EnableCustomReviveHealthPatch, delegate
				{
					harmony.PatchAll(typeof(PlayerReviveHealthPatch));
				}, delegate
				{
					harmony.Unpatch((MethodBase)AccessTools.Method(typeof(PlayerAvatar), "ReviveRPC", (Type[])null, (Type[])null), AccessTools.Method(typeof(PlayerReviveHealthPatch), "ReviveRPC_Postfix", (Type[])null, (Type[])null));
				}, "Custom Revive Health"),
				(Configuration.EnableExtractionHealPatch, delegate
				{
					harmony.PatchAll(typeof(ExtractionPointHealPatch));
				}, delegate
				{
					harmony.Unpatch((MethodBase)AccessTools.Method(typeof(ExtractionPoint), "StateSet", (Type[])null, (Type[])null), AccessTools.Method(typeof(ExtractionPointHealPatch), "StateSet_Postfix", (Type[])null, (Type[])null));
				}, "Extraction Heal"),
				(Configuration.EnableHealthRegenPatch, delegate
				{
					harmony.PatchAll(typeof(HealthRegenPatch));
				}, delegate
				{
					harmony.Unpatch((MethodBase)AccessTools.Method(typeof(LevelGenerator), "GenerateDone", (Type[])null, (Type[])null), AccessTools.Method(typeof(HealthRegenPatch), "Start_Postfix", (Type[])null, (Type[])null));
				}, "Health Regeneration"),
				(Configuration.EnableFullHealthAtStartPatch, delegate
				{
					harmony.PatchAll(typeof(FullHealthAtStartPatch));
				}, delegate
				{
					harmony.Unpatch((MethodBase)AccessTools.Method(typeof(LevelGenerator), "GenerateDone", (Type[])null, (Type[])null), AccessTools.Method(typeof(FullHealthAtStartPatch), "GenerateDone_Postfix", (Type[])null, (Type[])null));
				}, "Full Health At Start"),
				(Configuration.EnableTeamHealthPackPatch, delegate
				{
					//IL_002d: Unknown result type (might be due to invalid IL or missing references)
					//IL_003a: Expected O, but got Unknown
					harmony.Patch((MethodBase)AccessTools.Method(typeof(ItemHealthPack), "UsedRPC", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(ItemHealthPackPatch), "TeamHealthPackSync", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}, delegate
				{
					harmony.Unpatch((MethodBase)AccessTools.Method(typeof(ItemHealthPack), "UsedRPC", (Type[])null, (Type[])null), AccessTools.Method(typeof(ItemHealthPackPatch), "TeamHealthPackSync", (Type[])null, (Type[])null));
				}, "Health Pack Team Healing")
			};
			(ConfigEntry<bool>, Action, Action, string)[] array = patchArray;
			for (int i = 0; i < array.Length; i++)
			{
				var (configEntry, enablePatch, disablePatch, description) = array[i];
				UpdatePatchFromConfig(configEntry, enablePatch, disablePatch, description);
				configEntry.SettingChanged += delegate
				{
					UpdatePatchFromConfig(configEntry, enablePatch, disablePatch, description);
				};
			}
		}

		private void UpdatePatchFromConfig(ConfigEntry<bool> configEntry, Action enablePatch, Action disablePatch, string description)
		{
			if (configEntry.Value)
			{
				enablePatch();
				Log.LogInfo((object)(description + " patch enabled."));
			}
			else
			{
				disablePatch();
				Log.LogInfo((object)(description + " patch disabled."));
			}
		}
	}
}
namespace BetterHeals.Patches
{
	internal static class ExtractionPointHealPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(ExtractionPoint), "StateSet")]
		private static void StateSet_Postfix(ExtractionPoint __instance, State newState)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			if ((int)newState != 7 || SemiFunc.RunIsShop() || !PhotonNetwork.IsMasterClient)
			{
				return;
			}
			int num = Configuration.ExtractionHealAmount.Value;
			foreach (PlayerAvatar player in GameDirector.instance.PlayerList)
			{
				if ((Object)(object)player != (Object)null && (Object)(object)player.playerHealth != (Object)null)
				{
					if (Configuration.EnableFullReviveHealth.Value)
					{
						int num2 = TeamHealsPlugin.health_ref.Invoke(player.playerHealth);
						num = TeamHealsPlugin.max_health_ref.Invoke(player.playerHealth) - num2;
					}
					FieldInfo field = typeof(PlayerHealth).GetField("health", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					int num3 = ((!(field != null)) ? 1 : ((int)field.GetValue(player.playerHealth)));
					FieldInfo field2 = typeof(PlayerAvatar).GetField("isDisabled", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					bool flag = field2 != null && (bool)field2.GetValue(player);
					if (num3 > 0 && !flag)
					{
						player.playerHealth.HealOther(num, true);
					}
				}
			}
			TeamHealsPlugin.Log.LogInfo((object)$"All alive players healed to {num} after extraction.");
		}
	}
	internal static class FullHealthAtStartPatch
	{
		[HarmonyPatch(typeof(LevelGenerator), "GenerateDone")]
		[HarmonyPostfix]
		private static void GenerateDone_Postfix()
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			RunManager instance = RunManager.instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.levelCurrent == (Object)(object)instance.levelMainMenu) && !((Object)(object)instance.levelCurrent == (Object)(object)instance.levelLobbyMenu) && !((Object)(object)instance.levelCurrent == (Object)(object)instance.levelLobby) && !((Object)(object)instance.levelCurrent == (Object)(object)instance.levelShop) && !((Object)(object)instance.levelCurrent == (Object)(object)instance.levelRecording) && !((Object)(object)instance.levelCurrent == (Object)(object)instance.levelSplashScreen) && PhotonNetwork.IsMasterClient)
			{
				new GameObject("HealCoroutineRunner").AddComponent<HealRunner>();
			}
		}
	}
	public class HealRunner : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <HealAllPlayersToFull>d__1 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public HealRunner <>4__this;

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

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

			[DebuggerHidden]
			public <HealAllPlayersToFull>d__1(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;
				HealRunner healRunner = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(1f);
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					TeamHealsPlugin.Log.LogInfo((object)"Proceeding to heal all players to full health.");
					if ((Object)(object)GameDirector.instance == (Object)null || GameDirector.instance.PlayerList == null)
					{
						TeamHealsPlugin.Log.LogWarning((object)"GameDirector.instance or PlayerList is null.");
						Object.Destroy((Object)(object)((Component)healRunner).gameObject);
						return false;
					}
					List<PlayerAvatar> playerList = GameDirector.instance.PlayerList;
					FieldInfo field = typeof(PlayerHealth).GetField("health", BindingFlags.Instance | BindingFlags.NonPublic);
					FieldInfo field2 = typeof(PlayerHealth).GetField("maxHealth", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field == null || field2 == null)
					{
						TeamHealsPlugin.Log.LogError((object)"Could not find health or maxHealth fields via reflection.");
						Object.Destroy((Object)(object)((Component)healRunner).gameObject);
						return false;
					}
					foreach (PlayerAvatar item in playerList)
					{
						if ((Object)(object)item != (Object)null && (Object)(object)item.playerHealth != (Object)null)
						{
							int num2 = (int)field.GetValue(item.playerHealth);
							int num3 = (int)field2.GetValue(item.playerHealth);
							int num4 = num3 - num2;
							TeamHealsPlugin.Log.LogInfo((object)$"Player {item.photonView.Owner.NickName} current health: {num2}, max health: {num3}, calculated heal amount: {num4}");
							if (num4 > 0)
							{
								item.playerHealth.HealOther(num4, true);
								TeamHealsPlugin.Log.LogInfo((object)$"Healed player {item.photonView.Owner.NickName} to full health: {num3}");
							}
						}
					}
					Object.Destroy((Object)(object)((Component)healRunner).gameObject);
					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 void Awake()
		{
			((MonoBehaviour)this).StartCoroutine(HealAllPlayersToFull());
		}

		[IteratorStateMachine(typeof(<HealAllPlayersToFull>d__1))]
		private IEnumerator HealAllPlayersToFull()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <HealAllPlayersToFull>d__1(0)
			{
				<>4__this = this
			};
		}
	}
	public class RegenUpdater : MonoBehaviour
	{
		private float updateThrottle;

		public void Init()
		{
		}

		private void Update()
		{
			RunManager instance = RunManager.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.levelCurrent == (Object)(object)instance.levelMainMenu || (Object)(object)instance.levelCurrent == (Object)(object)instance.levelLobbyMenu || (Object)(object)instance.levelCurrent == (Object)(object)instance.levelLobby || (Object)(object)instance.levelCurrent == (Object)(object)instance.levelShop || (Object)(object)instance.levelCurrent == (Object)(object)instance.levelRecording || (Object)(object)instance.levelCurrent == (Object)(object)instance.levelSplashScreen || !Configuration.EnableHealthRegenPatch.Value)
			{
				return;
			}
			updateThrottle += Time.deltaTime;
			if (updateThrottle < (float)Configuration.CustomRegenIntervalAmount.Value)
			{
				return;
			}
			updateThrottle = 0f;
			int value = Configuration.HealthRegenAmount.Value;
			foreach (PlayerAvatar player in GameDirector.instance.PlayerList)
			{
				if ((Object)(object)player.playerHealth != (Object)null && TeamHealsPlugin.health_ref.Invoke(player.playerHealth) > 0)
				{
					player.playerHealth.HealOther(value, false);
				}
			}
			TeamHealsPlugin.Log.LogInfo((object)$"Players healed by regeneration: {value}");
		}
	}
	internal static class HealthRegenPatch
	{
		[HarmonyPatch(typeof(LevelGenerator), "GenerateDone")]
		[HarmonyPostfix]
		private static void Start_Postfix(PlayerController __instance)
		{
			RunManager instance = RunManager.instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.levelCurrent == (Object)(object)instance.levelMainMenu) && !((Object)(object)instance.levelCurrent == (Object)(object)instance.levelLobbyMenu) && !((Object)(object)instance.levelCurrent == (Object)(object)instance.levelLobby) && !((Object)(object)instance.levelCurrent == (Object)(object)instance.levelShop) && !((Object)(object)instance.levelCurrent == (Object)(object)instance.levelRecording) && !((Object)(object)instance.levelCurrent == (Object)(object)instance.levelSplashScreen) && (!GameManager.Multiplayer() || PhotonNetwork.IsMasterClient) && (Object)(object)__instance != (Object)null)
			{
				GameObject gameObject = ((Component)__instance).gameObject;
				if ((Object)(object)gameObject.GetComponent<RegenUpdater>() == (Object)null)
				{
					gameObject.AddComponent<RegenUpdater>().Init();
					TeamHealsPlugin.Log.LogInfo((object)("RegenUpdater attached to " + ((Object)__instance).name + "."));
				}
			}
		}
	}
	internal static class ItemHealthPackPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(ItemHealthPack), "Start")]
		private static void OverrideHealAmount(ItemHealthPack __instance)
		{
			float num = (float)Math.Round(Configuration.HealAmountMultiplier.Value, 4);
			if (num == 1f)
			{
				TeamHealsPlugin.Log.LogInfo((object)"Heal amount multiplier is 1. No changes made to health pack heal amount.");
			}
			else
			{
				__instance.healAmount = (int)Math.Ceiling((float)__instance.healAmount * num);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(ItemAttributes), "Start")]
		private static void OverrideHealthPackName(ItemAttributes __instance)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			if (!((Object)(object)__instance.item != (Object)null) || (int)__instance.item.itemType != 8)
			{
				return;
			}
			ItemHealthPack component = ((Component)__instance).GetComponent<ItemHealthPack>();
			if ((Object)(object)component != (Object)null)
			{
				int healAmount = component.healAmount;
				FieldInfo field = typeof(ItemAttributes).GetField("itemName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					string text = (string)field.GetValue(__instance);
					if (!string.IsNullOrEmpty(text))
					{
						string text2 = Regex.Replace(text, "\\(\\d+\\)", $"({healAmount})");
						field.SetValue(__instance, text2);
						TeamHealsPlugin.Log.LogInfo((object)("Health pack name changed from '" + text + "' to '" + text2 + "'"));
					}
					else
					{
						TeamHealsPlugin.Log.LogWarning((object)"itemName value is null or empty in ItemAttributes.Start postfix.");
					}
				}
				else
				{
					TeamHealsPlugin.Log.LogWarning((object)"itemName field not found in ItemAttributes.");
				}
			}
			else
			{
				TeamHealsPlugin.Log.LogWarning((object)"ItemHealthPack component not found on ItemAttributes.");
			}
		}

		private static void TeamHealthPackSync(ItemHealthPack __instance)
		{
			ItemToggle val = TeamHealsPlugin.item_toggle_ref.Invoke(__instance);
			PlayerAvatar val2 = SemiFunc.PlayerAvatarGetFromPhotonID(TeamHealsPlugin.player_photon_id_ref.Invoke(val));
			List<PlayerAvatar> list = SemiFunc.PlayerGetAll();
			foreach (PlayerAvatar item in list)
			{
				if (item.photonView.ViewID != val2.photonView.ViewID)
				{
					if (Configuration.EnableEqualSplitTeamHealth.Value)
					{
						item.playerHealth.HealOther(__instance.healAmount / list.Count, true);
					}
					else
					{
						item.playerHealth.HealOther(__instance.healAmount, true);
					}
					TeamHealsPlugin.Log.LogInfo((object)($"Healed player {item.photonView.ViewID} for {__instance.healAmount} HP " + $"(used by {val2.photonView.ViewID})"));
				}
			}
			TeamHealsPlugin.Log.LogInfo((object)$"Health pack used by player {val2.photonView.ViewID} healed all teammates");
		}
	}
	internal static class PlayerReviveHealthPatch
	{
		[HarmonyPatch(typeof(PlayerAvatar), "ReviveRPC")]
		[HarmonyPostfix]
		private static void ReviveRPC_Postfix(PlayerAvatar __instance)
		{
			int num = Configuration.CustomReviveHealthAmount.Value - 1;
			if (__instance.photonView.IsMine)
			{
				if (Configuration.EnableFullReviveHealth.Value)
				{
					int num2 = TeamHealsPlugin.health_ref.Invoke(__instance.playerHealth);
					num = TeamHealsPlugin.max_health_ref.Invoke(__instance.playerHealth) - num2;
				}
				__instance.playerHealth.HealOther(num, true);
				TeamHealsPlugin.Log.LogInfo((object)$"Player revived with custom health: {num}");
			}
		}
	}
	[HarmonyPatch(typeof(PunManager), "ShopPopulateItemVolumes")]
	internal class PunManagerPatch
	{
		private static readonly FieldRef<PunManager, ShopManager> shop_manager_ref = AccessTools.FieldRefAccess<PunManager, ShopManager>("shopManager");

		public static bool Prefix(PunManager __instance)
		{
			List<Item> list = new HashSet<Item>(shop_manager_ref.Invoke(__instance).potentialItemHealthPacks).Distinct().ToList();
			for (int i = 0; i < list.Count; i++)
			{
				string itemName = Regex.Replace(list[i].itemName, "\\d+", delegate(Match match)
				{
					int num = int.Parse(match.Value);
					return ((int)Math.Ceiling((float)num * Configuration.HealAmountMultiplier.Value)).ToString();
				});
				list[i].itemName = itemName;
			}
			return true;
		}
	}
}
namespace BetterHeals.Config
{
	internal class Configuration
	{
		public static ConfigEntry<bool> EnableFullHealthAtStartPatch;

		public static ConfigEntry<bool> EnableTeamHealthPackPatch;

		public static ConfigEntry<bool> EnableEqualSplitTeamHealth;

		public static ConfigEntry<bool> EnableHealthRegenPatch;

		public static ConfigEntry<int> HealthRegenAmount;

		public static ConfigEntry<int> CustomRegenIntervalAmount;

		public static ConfigEntry<float> HealAmountMultiplier;

		public static ConfigEntry<bool> EnableCustomReviveHealthPatch;

		public static ConfigEntry<int> CustomReviveHealthAmount;

		public static ConfigEntry<bool> EnableFullReviveHealth;

		public static ConfigEntry<bool> EnableExtractionHealPatch;

		public static ConfigEntry<bool> EnableExtractionFullHeal;

		public static ConfigEntry<int> ExtractionHealAmount;

		public static void Init(ConfigFile config)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Expected O, but got Unknown
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Expected O, but got Unknown
			HealAmountMultiplier = config.Bind<float>("General Health Settings", "HealthPackAmountMultiplier", 1f, new ConfigDescription("Multiplier applied to the health pack healing", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>()));
			EnableFullHealthAtStartPatch = config.Bind<bool>("General Health Settings", "EnableFullHealthAtStart", false, "If enabled, players will start the match with full health");
			EnableHealthRegenPatch = config.Bind<bool>("General Health Settings", "EnableHealthRegen", false, "If enabled, players will slowly regenerate health over time");
			HealthRegenAmount = config.Bind<int>("General Health Settings", "HealthRegenAmount", 10, new ConfigDescription("The amount of health players will regenerate each interval if the Health Regeneration patch is enabled", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>()));
			CustomRegenIntervalAmount = config.Bind<int>("General Health Settings", "CustomRegenIntervalAmount", 60, new ConfigDescription("The interval in seconds at which players will regenerate health if the Health Regeneration patch is enabled", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 120), Array.Empty<object>()));
			EnableExtractionHealPatch = config.Bind<bool>("General Health Settings", "EnableExtractionHeal", true, "Enable the patch that heals alive players after extraction is completed");
			EnableExtractionFullHeal = config.Bind<bool>("General Health Settings", "ExtractionFullHeal", false, "If enabled, players will be healed to full health upon extraction regardless of the ExtractionHealAmount setting");
			ExtractionHealAmount = config.Bind<int>("General Health Settings", "ExtractionHealAmount", 20, new ConfigDescription("The health that alive players receive after extraction is completed", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>()));
			EnableTeamHealthPackPatch = config.Bind<bool>("Team Health Settings", "EnableTeamHealthPack", true, "Enable the patch that allows health packs to heal all teammates");
			EnableEqualSplitTeamHealth = config.Bind<bool>("Team Health Settings", "EnableEqualSplitTeamHealth", false, "If enabled, health packs will split their healing amount equally among all teammates");
			EnableCustomReviveHealthPatch = config.Bind<bool>("Team Health Settings", "EnableCustomReviveHealth", true, "Enable the patch that sets a custom value to the health received when a player is revived");
			EnableFullReviveHealth = config.Bind<bool>("Team Health Settings", "FullReviveHealth", false, "If enabled, players will be revived with full health regardless of the CustomReviveHealthAmount setting");
			CustomReviveHealthAmount = config.Bind<int>("Team Health Settings", "CustomReviveHealthAmount", 20, new ConfigDescription("The health that a player receives upon revival", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
		}
	}
}