Decompiled source of Medic v1.1.3

plugins/callmehill-Medic/Medic!.dll

Decompiled 3 days 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.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Medic!")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+fc858f24aa0a9890a2fa402bf499e3760b334511")]
[assembly: AssemblyProduct("Medic!")]
[assembly: AssemblyTitle("Medic!")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace Medic_
{
	public sealed class AvatarReviveRelay : MonoBehaviourPun
	{
		[PunRPC]
		public void SyncRevivedHealth(int actorNumber, float health)
		{
			PlayerAvatar avatarByActorNumber = MedicHeadReviver.GetAvatarByActorNumber(actorNumber);
			if ((Object)(object)avatarByActorNumber != (Object)null)
			{
				MedicHeadReviver.SetHealth(avatarByActorNumber, health);
			}
		}

		[PunRPC]
		public void SyncReviverHealth(int actorNumber, float health)
		{
			PlayerAvatar avatarByActorNumber = MedicHeadReviver.GetAvatarByActorNumber(actorNumber);
			if ((Object)(object)avatarByActorNumber != (Object)null)
			{
				MedicHeadReviver.SetHealth(avatarByActorNumber, health);
			}
		}

		[PunRPC]
		public void NotifyRevived(int actorNumber)
		{
			((MonoBehaviour)this).StartCoroutine(NotifyRevivedDelayed(actorNumber));
		}

		private IEnumerator NotifyRevivedDelayed(int actorNumber)
		{
			yield return null;
			yield return null;
			yield return (object)new WaitForSeconds(0.2f);
			PlayerAvatar local = MedicHeadReviver.GetLocalAvatar();
			if ((Object)(object)local != (Object)null && local.photonView.IsMine && local.photonView.OwnerActorNr == actorNumber)
			{
				MedicHeadReviver.SendRevivedChatMessage(local);
			}
		}
	}
	[BepInPlugin("com.callmehill.medic", "Medic Mod", "1.1.3")]
	public class MedicPlugin : BaseUnityPlugin
	{
		internal static bool IsHoldingPlayerDeathHead;

		internal static string? PlayerDeathHeadOwner;

		internal static PlayerDeathHead? HeldPlayerDeathHead;

		internal static ConfigEntry<float>? HealthTransferAmount;

		internal static ConfigEntry<bool>? EnableGratitude;

		internal static ConfigEntry<string>? DeniedSoundNativeName;

		internal static AudioClip? DeniedSoundClip;

		internal static ConfigEntry<float>? DenyActionCooldown;

		private static float _lastDenySoundTime = -999f;

		private static AudioSource? _localAudioSource;

		private static float _lastAudioTime = -999f;

		internal static ConfigEntry<bool>? EnableFailedReviveMessage;

		internal static ConfigEntry<string>? FailedReviveMessage;

		internal static readonly List<string> FailedRevivePhrases = new List<string>();

		private static readonly string[] DefaultFailedPhrases = new string[5] { "I don't have enough health to revive you!", "Need more health to revive!", "Can't revive - low on health!", "Not enough HP to help you up!", "Too weak to revive you right now!" };

		internal static ConfigEntry<float>? ChatCooldownDuration;

		internal static float _lastFailedReviveMessageTime = -999f;

		internal static ConfigEntry<string>? PhrasesFileName;

		internal static ConfigEntry<string>? FallbackPhrases;

		internal static readonly List<string> GratitudePhrases = new List<string>();

		private static readonly string[] DefaultPhrases = new string[5] { "Wow! Thank you, friend!", "You saved me!", "Back in the fight!", "Clutch revive!", "I owe you one!" };

		private static readonly Random s_rng = new Random();

		internal static string? PluginDirectory;

		private static bool _initialized;

		private Harmony? _harmony;

		private void Awake()
		{
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Expected O, but got Unknown
			if (_initialized)
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			_initialized = true;
			PluginDirectory = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Medic! mod activated.");
			HealthTransferAmount = ((BaseUnityPlugin)this).Config.Bind<float>("General", "HealthTransferAmount", 20f, "Amount of health transferred from reviver to revivee.");
			EnableGratitude = ((BaseUnityPlugin)this).Config.Bind<bool>("Chat", "EnableGratitude", true, "Enable or disable the revive gratitude chat message.");
			PhrasesFileName = ((BaseUnityPlugin)this).Config.Bind<string>("Chat", "PhrasesFile", "gratitude_phrases.txt", "Text file name to load phrases from (one phrase per line). Searched in the plugin directory and BepInEx/config.");
			FallbackPhrases = ((BaseUnityPlugin)this).Config.Bind<string>("Chat", "FallbackPhrases", "Wow! Thank you, friend!|You saved me!|I owe you one!|Back in the fight!|That was clutch!", "Fallback phrases separated by |, used if the phrases file is missing or empty.");
			DeniedSoundNativeName = ((BaseUnityPlugin)this).Config.Bind<string>("Sound", "DeniedSoundNativeName", "soundDeny", "Native AudioClip name played when chat input exceeds the character limit.");
			EnableFailedReviveMessage = ((BaseUnityPlugin)this).Config.Bind<bool>("Chat", "EnableFailedReviveMessage", true, "Enable or disable the failed revive chat message.");
			FailedReviveMessage = ((BaseUnityPlugin)this).Config.Bind<string>("Chat", "FailedReviveMessage", "I don't have enough health to revive you!|Need more health to revive!|Can't revive - low on health!|Not enough HP to help you up!|Too weak to revive you right now!", "Failed revive messages separated by |, randomly selected when a revive fails due to low health.");
			ChatCooldownDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Chat", "ChatCooldownDuration", 1f, "Cooldown in seconds between failed revive chat messages to prevent spam.");
			DenyActionCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Performance", "DenyActionCooldown", 0.5f, "Cooldown in seconds between deny actions when health is insufficient.");
			LoadFailedRevivePhrases();
			((MonoBehaviour)this).StartCoroutine(BindDeniedSound());
			LoadPhrases();
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			_harmony = new Harmony("com.callmehill.medic");
			_harmony.PatchAll();
		}

		private IEnumerator BindDeniedSound()
		{
			while ((Object)(object)MenuManager.instance == (Object)null)
			{
				yield return null;
			}
			Sound sound = MenuManager.instance.soundDeny;
			if (sound != null && sound.Sounds != null && sound.Sounds.Length != 0)
			{
				DeniedSoundClip = sound.Sounds[0];
			}
			if ((Object)(object)DeniedSoundClip == (Object)null && DeniedSoundNativeName != null)
			{
				DeniedSoundClip = ((IEnumerable<AudioClip>)Resources.FindObjectsOfTypeAll<AudioClip>()).FirstOrDefault((Func<AudioClip, bool>)((AudioClip c) => ((Object)c).name == DeniedSoundNativeName.Value));
			}
		}

		private void OnDestroy()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			_initialized = false;
			GameObject val = new GameObject("MedicPlugin");
			val.AddComponent<MedicPlugin>();
		}

		internal static void PlayDenySound(Vector3 position)
		{
			//IL_0073: 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_0054: Expected O, but got Unknown
			if ((Object)(object)DeniedSoundClip == (Object)null)
			{
				return;
			}
			float num = 0.3f;
			if (!(Time.time - _lastAudioTime < num))
			{
				_lastAudioTime = Time.time;
				if ((Object)(object)_localAudioSource == (Object)null)
				{
					GameObject val = new GameObject("MedicAudio");
					_localAudioSource = val.AddComponent<AudioSource>();
					Object.DontDestroyOnLoad((Object)(object)val);
				}
				((Component)_localAudioSource).transform.position = position;
				_localAudioSource.PlayOneShot(DeniedSoundClip);
			}
		}

		private void Update()
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown((KeyCode)104))
			{
				if ((Object)(object)HeldPlayerDeathHead == (Object)null)
				{
					return;
				}
				try
				{
					PlayerAvatar localAvatar = MedicHeadReviver.GetLocalAvatar();
					if ((Object)(object)localAvatar == (Object)null)
					{
						return;
					}
					if (!MedicHeadReviver.HasRequiredHealth(localAvatar))
					{
						float num = DenyActionCooldown?.Value ?? 0.5f;
						if (!(Time.time - _lastDenySoundTime < num))
						{
							_lastDenySoundTime = Time.time;
							Vector3 position = ((Component)localAvatar).transform.position;
							PlayDenySound(position);
							MedicHeadReviver.SendFailedReviveMessage(localAvatar, HeldPlayerDeathHead);
						}
						return;
					}
					if (PhotonNetwork.IsMasterClient)
					{
						MedicHeadReviver.ReviveHead(HeldPlayerDeathHead, localAvatar);
					}
					else
					{
						MedicHeadReviver component = ((Component)HeldPlayerDeathHead).GetComponent<MedicHeadReviver>();
						if (component != null)
						{
							((MonoBehaviourPun)component).photonView.RPC("RequestRevive", (RpcTarget)2, Array.Empty<object>());
						}
					}
				}
				catch (Exception)
				{
				}
			}
			if (Input.GetKey((KeyCode)306) && Input.GetKeyDown((KeyCode)112))
			{
				LoadPhrases();
			}
		}

		internal static void LoadPhrases()
		{
			try
			{
				GratitudePhrases.Clear();
				string text = PhrasesFileName?.Value ?? "gratitude_phrases.txt";
				List<string> list = new List<string>();
				if (!string.IsNullOrEmpty(PluginDirectory))
				{
					list.Add(Path.Combine(PluginDirectory, text));
				}
				list.Add(Path.Combine(Paths.ConfigPath, text));
				if (File.Exists(text))
				{
					list.Add(text);
				}
				foreach (string item2 in list)
				{
					if (!File.Exists(item2))
					{
						continue;
					}
					string[] array = File.ReadAllLines(item2);
					foreach (string text2 in array)
					{
						string text3 = (text2 ?? string.Empty).Trim();
						if (text3.Length != 0 && !text3.StartsWith("#"))
						{
							string item = ((text3.Length > 160) ? text3.Substring(0, 160).TrimEnd() : text3);
							GratitudePhrases.Add(item);
						}
					}
					if (GratitudePhrases.Count > 0)
					{
						return;
					}
				}
				string text4 = FallbackPhrases?.Value ?? string.Empty;
				string[] array2 = text4.Split(new char[1] { '|' }, StringSplitOptions.RemoveEmptyEntries);
				foreach (string text5 in array2)
				{
					string text6 = text5.Trim();
					if (text6.Length > 0)
					{
						GratitudePhrases.Add(text6);
					}
				}
				if (GratitudePhrases.Count == 0)
				{
					GratitudePhrases.AddRange(DefaultPhrases);
				}
			}
			catch (Exception)
			{
				if (GratitudePhrases.Count == 0)
				{
					GratitudePhrases.AddRange(DefaultPhrases);
				}
			}
		}

		internal static string GetRandomGratitude()
		{
			if (GratitudePhrases.Count == 0)
			{
				LoadPhrases();
			}
			int index = s_rng.Next(GratitudePhrases.Count);
			return GratitudePhrases[index];
		}

		internal static void LoadFailedRevivePhrases()
		{
			try
			{
				FailedRevivePhrases.Clear();
				string text = FailedReviveMessage?.Value ?? string.Empty;
				string[] array = text.Split(new char[1] { '|' }, StringSplitOptions.RemoveEmptyEntries);
				foreach (string text2 in array)
				{
					string text3 = text2.Trim();
					if (text3.Length > 0)
					{
						FailedRevivePhrases.Add(text3);
					}
				}
				if (FailedRevivePhrases.Count == 0)
				{
					FailedRevivePhrases.AddRange(DefaultFailedPhrases);
				}
			}
			catch (Exception)
			{
				if (FailedRevivePhrases.Count == 0)
				{
					FailedRevivePhrases.AddRange(DefaultFailedPhrases);
				}
			}
		}

		internal static string GetRandomFailedReviveMessage()
		{
			if (FailedRevivePhrases.Count == 0)
			{
				LoadFailedRevivePhrases();
			}
			int index = s_rng.Next(FailedRevivePhrases.Count);
			return FailedRevivePhrases[index];
		}
	}
	[HarmonyPatch(typeof(PhysGrabber), "PhysGrabStarted")]
	internal class PhysGrabberStartedPatch
	{
		private static readonly FieldInfo GrabbedPhysGrabObjectField = AccessTools.Field(typeof(PhysGrabber), "grabbedPhysGrabObject");

		private static readonly FieldInfo PlayerAvatarField = AccessTools.Field(typeof(PlayerDeathHead), "playerAvatar");

		private static readonly FieldInfo PlayerNameField = AccessTools.Field(typeof(PlayerAvatar), "playerName");

		private static void Postfix(PhysGrabber __instance)
		{
			object? value = GrabbedPhysGrabObjectField.GetValue(__instance);
			PhysGrabObject val = (PhysGrabObject)((value is PhysGrabObject) ? value : null);
			MedicPlugin.IsHoldingPlayerDeathHead = false;
			MedicPlugin.PlayerDeathHeadOwner = null;
			MedicPlugin.HeldPlayerDeathHead = null;
			PlayerDeathHead val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<PlayerDeathHead>() : null);
			if ((Object)(object)val2 != (Object)null)
			{
				MedicPlugin.IsHoldingPlayerDeathHead = true;
				MedicPlugin.HeldPlayerDeathHead = val2;
				object? value2 = PlayerAvatarField.GetValue(val2);
				PlayerAvatar val3 = (PlayerAvatar)((value2 is PlayerAvatar) ? value2 : null);
				if ((Object)(object)val3 != (Object)null)
				{
					MedicPlugin.PlayerDeathHeadOwner = PlayerNameField.GetValue(val3) as string;
				}
			}
		}
	}
	[HarmonyPatch(typeof(PhysGrabber), "PhysGrabEnded")]
	internal class PhysGrabberEndedPatch
	{
		private static void Postfix()
		{
			MedicPlugin.IsHoldingPlayerDeathHead = false;
			MedicPlugin.PlayerDeathHeadOwner = null;
			MedicPlugin.HeldPlayerDeathHead = null;
		}
	}
	[HarmonyPatch(typeof(PlayerDeathHead), "Start")]
	internal class PlayerDeathHeadStartPatch
	{
		private static void Postfix(PlayerDeathHead __instance)
		{
			if ((Object)(object)((Component)__instance).GetComponent<MedicHeadReviver>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<MedicHeadReviver>();
			}
		}
	}
	[HarmonyPatch(typeof(PlayerAvatar), "Awake")]
	internal static class PlayerAvatar_Awake_AddRelay
	{
		private static void Postfix(PlayerAvatar __instance)
		{
			if ((Object)(object)((Component)__instance).GetComponent<AvatarReviveRelay>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<AvatarReviveRelay>();
			}
		}
	}
	internal class MedicHeadReviver : MonoBehaviourPun
	{
		private static readonly FieldInfo PlayerAvatarField = AccessTools.Field(typeof(PlayerDeathHead), "playerAvatar");

		private static readonly FieldInfo PlayerNameField = AccessTools.Field(typeof(PlayerAvatar), "playerName");

		private static readonly Type? PlayerHealthType = AccessTools.TypeByName("PlayerHealth");

		private static readonly FieldInfo? HealthField = AccessTools.Field(PlayerHealthType, "health");

		private static readonly FieldInfo? HealthSetField = AccessTools.Field(PlayerHealthType, "healthSet");

		private static readonly FieldInfo? MaxHealthField = AccessTools.Field(PlayerHealthType, "maxHealth");

		private static PlayerAvatar? _cachedLocalAvatar;

		private static float _lastAvatarCheckTime = -999f;

		private static readonly Dictionary<int, float> _healthCache = new Dictionary<int, float>();

		private static float _lastHealthCheckTime = -999f;

		private static MethodInfo? _playerChatMessageSendMethod;

		internal static PlayerAvatar? GetLocalAvatar()
		{
			if (Time.time - _lastAvatarCheckTime < 1f && (Object)(object)_cachedLocalAvatar != (Object)null)
			{
				return _cachedLocalAvatar;
			}
			_lastAvatarCheckTime = Time.time;
			PlayerAvatar[] array = Object.FindObjectsOfType<PlayerAvatar>();
			foreach (PlayerAvatar val in array)
			{
				if (val.photonView.IsMine)
				{
					_cachedLocalAvatar = val;
					return val;
				}
			}
			_cachedLocalAvatar = null;
			return null;
		}

		internal static PlayerAvatar? GetAvatarByActorNumber(int actorNumber)
		{
			PlayerAvatar[] array = Object.FindObjectsOfType<PlayerAvatar>();
			foreach (PlayerAvatar val in array)
			{
				if (val.photonView.OwnerActorNr == actorNumber)
				{
					return val;
				}
			}
			return null;
		}

		private static float GetHealth(PlayerAvatar avatar)
		{
			Component val = ((PlayerHealthType != null) ? ((Component)avatar).GetComponent(PlayerHealthType) : null);
			if ((Object)(object)val != (Object)null && HealthField != null)
			{
				object value = HealthField.GetValue(val);
				if (value != null)
				{
					return Convert.ToSingle(value);
				}
			}
			return 0f;
		}

		private static float GetCachedHealth(PlayerAvatar avatar)
		{
			int instanceID = ((Object)avatar).GetInstanceID();
			if (Time.time - _lastHealthCheckTime < 0.5f && _healthCache.TryGetValue(instanceID, out var value))
			{
				return value;
			}
			float health = GetHealth(avatar);
			_healthCache[instanceID] = health;
			_lastHealthCheckTime = Time.time;
			if (_healthCache.Count > 100)
			{
				_healthCache.Clear();
			}
			return health;
		}

		internal static void SetHealth(PlayerAvatar avatar, float amount)
		{
			Component val = ((PlayerHealthType != null) ? ((Component)avatar).GetComponent(PlayerHealthType) : null);
			if ((Object)(object)val != (Object)null && HealthField != null)
			{
				try
				{
					object value = Convert.ChangeType(amount, HealthField.FieldType);
					HealthField.SetValue(val, value);
					HealthSetField?.SetValue(val, true);
				}
				catch (InvalidCastException)
				{
				}
			}
		}

		private static float GetMaxHealth(PlayerAvatar avatar)
		{
			Component val = ((PlayerHealthType != null) ? ((Component)avatar).GetComponent(PlayerHealthType) : null);
			if ((Object)(object)val != (Object)null && MaxHealthField != null)
			{
				object value = MaxHealthField.GetValue(val);
				if (value != null)
				{
					return Convert.ToSingle(value);
				}
			}
			return 100f;
		}

		private static void SendChatMessage(PlayerAvatar avatar, string message)
		{
			try
			{
				if ((object)_playerChatMessageSendMethod == null)
				{
					_playerChatMessageSendMethod = AccessTools.Method(typeof(PlayerAvatar), "ChatMessageSend", new Type[1] { typeof(string) }, (Type[])null);
				}
				if (!(_playerChatMessageSendMethod == null))
				{
					_playerChatMessageSendMethod.Invoke(avatar, new object[1] { message });
				}
			}
			catch (Exception)
			{
			}
		}

		internal static void SendRevivedChatMessage(PlayerAvatar avatar)
		{
			if (MedicPlugin.EnableGratitude == null || MedicPlugin.EnableGratitude.Value)
			{
				string randomGratitude = MedicPlugin.GetRandomGratitude();
				SendChatMessage(avatar, randomGratitude);
			}
		}

		internal static void SendFailedReviveMessage(PlayerAvatar avatar, PlayerDeathHead? head)
		{
			if (MedicPlugin.EnableFailedReviveMessage == null || !MedicPlugin.EnableFailedReviveMessage.Value)
			{
				return;
			}
			float num = MedicPlugin.ChatCooldownDuration?.Value ?? 1f;
			if (Time.time - MedicPlugin._lastFailedReviveMessageTime < num)
			{
				return;
			}
			string text = MedicPlugin.GetRandomFailedReviveMessage();
			if ((Object)(object)head != (Object)null)
			{
				object? value = PlayerAvatarField.GetValue(head);
				PlayerAvatar val = (PlayerAvatar)((value is PlayerAvatar) ? value : null);
				if ((Object)(object)val != (Object)null && PlayerNameField != null)
				{
					string text2 = PlayerNameField.GetValue(val) as string;
					if (!string.IsNullOrEmpty(text2))
					{
						text = text2 + ", " + text.ToLower();
					}
				}
			}
			MedicPlugin._lastFailedReviveMessageTime = Time.time;
			SendChatMessage(avatar, text);
		}

		internal static bool HasRequiredHealth(PlayerAvatar avatar)
		{
			float num = MedicPlugin.HealthTransferAmount?.Value ?? 20f;
			return GetCachedHealth(avatar) >= num + 1f;
		}

		internal static void ReviveHead(PlayerDeathHead? head, PlayerAvatar? reviver)
		{
			if ((Object)(object)head == (Object)null || (Object)(object)reviver == (Object)null)
			{
				return;
			}
			object? value = PlayerAvatarField.GetValue(head);
			PlayerAvatar val = (PlayerAvatar)((value is PlayerAvatar) ? value : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			float num = MedicPlugin.HealthTransferAmount?.Value ?? 20f;
			float health = GetHealth(reviver);
			if (!(health < num + 1f))
			{
				float num2 = health - num;
				SetHealth(reviver, num2);
				if ((Object)(object)reviver.photonView != (Object)null)
				{
					reviver.photonView.RPC("SyncReviverHealth", (RpcTarget)0, new object[2]
					{
						reviver.photonView.OwnerActorNr,
						num2
					});
				}
				val.photonView.RPC("ReviveRPC", (RpcTarget)0, new object[1] { true });
				float maxHealth = GetMaxHealth(val);
				float num3 = Mathf.Min(num, maxHealth);
				SetHealth(val, num3);
				val.photonView.RPC("SyncRevivedHealth", (RpcTarget)0, new object[2]
				{
					val.photonView.OwnerActorNr,
					num3
				});
				val.photonView.RPC("NotifyRevived", val.photonView.Owner, new object[1] { val.photonView.OwnerActorNr });
			}
		}

		[PunRPC]
		public void RequestRevive(PhotonMessageInfo info)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			PlayerAvatar avatarByActorNumber = GetAvatarByActorNumber(info.Sender.ActorNumber);
			ReviveHead(((Component)this).GetComponent<PlayerDeathHead>(), avatarByActorNumber);
		}
	}
}