Decompiled source of RepoMutantEnemies v0.8.0

Matsu.MergedEnemyMod.dll

Decompiled 11 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using REPOLib.Modules;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("Matsu.MergedEnemyMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Matsu.MergedEnemyMod")]
[assembly: AssemblyTitle("Matsu.MergedEnemyMod")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.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]
	[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;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Matsu.MergedEnemyMod
{
	internal static class FusionShared
	{
		private static ParticleScriptExplosion? _sharedExplosion;

		private static GameObject? _explosionPrefab;

		private static readonly List<PlayerAvatar> _noPlayers = new List<PlayerAvatar>();

		private static FieldInfo? _healthCurrentField;

		private static FieldInfo? _impactDetectorField;

		private static MethodInfo? _hurtMultiplierMethod;

		private static FieldInfo? _explSizeField;

		private static FieldInfo? _explDmgField;

		private static FieldInfo? _explDmgEnemyField;

		private const string AuraLightName = "MatsuMutationAura";

		private static FieldInfo? _tumbleField;

		private static FieldInfo? _tumblePhysGrabObjectField;

		private static FieldInfo? _clientPositionField;

		private static FieldInfo? _clientPositionCurrentField;

		private static FieldInfo? _visualPositionField;

		private static FieldInfo? _isDisabledField;

		public static List<PlayerAvatar> AllPlayers()
		{
			GameDirector instance = GameDirector.instance;
			if (!((Object)(object)instance != (Object)null) || instance.PlayerList == null)
			{
				return _noPlayers;
			}
			return instance.PlayerList;
		}

		public static bool NearestPlayerWithin(Vector3 from, float range)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			foreach (PlayerAvatar item in AllPlayers())
			{
				if (!((Object)(object)item == (Object)null) && Vector3.Distance(from, ((Component)item).transform.position) <= range)
				{
					return true;
				}
			}
			return false;
		}

		public static List<PlayerAvatar> PlayersInRadius(Vector3 center, float radius)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			List<PlayerAvatar> list = new List<PlayerAvatar>();
			foreach (PlayerAvatar item in AllPlayers())
			{
				if (!((Object)(object)item == (Object)null) && Vector3.Distance(center, ((Component)item).transform.position) <= radius)
				{
					list.Add(item);
				}
			}
			return list;
		}

		public static PlayerAvatar? NearestPlayer(Vector3 from, float maxDistance)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			PlayerAvatar result = null;
			float num = maxDistance;
			foreach (PlayerAvatar item in AllPlayers())
			{
				if (!((Object)(object)item == (Object)null))
				{
					float num2 = Vector3.Distance(from, ((Component)item).transform.position);
					if (num2 <= num)
					{
						num = num2;
						result = item;
					}
				}
			}
			return result;
		}

		public static List<PhysGrabObject> PhysObjectsInRadius(Vector3 center, float radius)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			HashSet<PhysGrabObject> hashSet = new HashSet<PhysGrabObject>();
			Collider[] array = Physics.OverlapSphere(center, radius);
			foreach (Collider val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					PhysGrabObject componentInParent = ((Component)val).GetComponentInParent<PhysGrabObject>();
					if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent.rb != (Object)null && !componentInParent.grabbed && (Object)(object)((Component)componentInParent).GetComponentInParent<EnemyParent>() == (Object)null)
					{
						hashSet.Add(componentInParent);
					}
				}
			}
			return new List<PhysGrabObject>(hashSet);
		}

		private static void SetExplField(ParticlePrefabExplosion pe, ref FieldInfo? cache, string name, object val)
		{
			try
			{
				if ((object)cache == null)
				{
					cache = typeof(ParticlePrefabExplosion).GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				cache?.SetValue(pe, val);
			}
			catch
			{
			}
		}

		public static ParticlePrefabExplosion? ExplodeAuthoritative(Vector3 pos, float size, int playerDmg, int enemyDmg, PhysGrabObject? ignoreSelf = null, Enemy? enemyHost = null)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			ParticlePrefabExplosion val = null;
			if ((Object)(object)_sharedExplosion == (Object)null)
			{
				_sharedExplosion = Object.FindObjectOfType<ParticleScriptExplosion>(true);
			}
			if ((Object)(object)_sharedExplosion != (Object)null)
			{
				try
				{
					val = _sharedExplosion.Spawn(pos, size, playerDmg, enemyDmg, 1f, false, false, 1f);
				}
				catch
				{
					val = null;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				if ((Object)(object)_explosionPrefab == (Object)null)
				{
					_explosionPrefab = Resources.Load<GameObject>("Effects/Part Prefab Explosion");
				}
				if ((Object)(object)_explosionPrefab != (Object)null)
				{
					val = Object.Instantiate<GameObject>(_explosionPrefab, pos, Quaternion.identity).GetComponent<ParticlePrefabExplosion>();
					if ((Object)(object)val != (Object)null)
					{
						SetExplField(val, ref _explSizeField, "explosionSize", size);
						SetExplField(val, ref _explDmgField, "explosionDamage", playerDmg);
						SetExplField(val, ref _explDmgEnemyField, "explosionDamageEnemy", enemyDmg);
						try
						{
							ParticleSystem particleFire = val.particleFire;
							if (particleFire != null)
							{
								particleFire.Play();
							}
							ParticleSystem particleSmoke = val.particleSmoke;
							if (particleSmoke != null)
							{
								particleSmoke.Play();
							}
							if ((Object)(object)val.light != (Object)null)
							{
								((Behaviour)val.light).enabled = true;
							}
						}
						catch
						{
						}
					}
				}
			}
			if ((Object)(object)val != (Object)null && (Object)(object)val.HurtCollider != (Object)null)
			{
				try
				{
					if ((Object)(object)ignoreSelf != (Object)null && val.HurtCollider.ignoreObjects != null)
					{
						val.HurtCollider.ignoreObjects.Add(ignoreSelf);
					}
					if ((Object)(object)enemyHost != (Object)null)
					{
						val.HurtCollider.enemyHost = enemyHost;
					}
				}
				catch
				{
				}
			}
			return val;
		}

		public static void ApplyMutationGlow(Transform root, Color color)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			try
			{
				Transform val = root.Find("MatsuMutationAura");
				Light val2;
				if ((Object)(object)val != (Object)null)
				{
					val2 = ((Component)val).GetComponent<Light>();
				}
				else
				{
					GameObject val3 = new GameObject("MatsuMutationAura");
					val3.transform.SetParent(root, false);
					val3.transform.localPosition = Vector3.zero;
					val2 = val3.AddComponent<Light>();
					val2.type = (LightType)2;
					val2.shadows = (LightShadows)0;
				}
				if ((Object)(object)val2 != (Object)null)
				{
					val2.color = color;
					val2.range = Plugin.MutationAuraRange.Value;
					val2.intensity = Plugin.MutationAuraIntensity.Value;
				}
			}
			catch
			{
			}
			Renderer[] componentsInChildren = ((Component)root).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val4 in componentsInChildren)
			{
				if ((Object)(object)val4 == (Object)null)
				{
					continue;
				}
				Material[] materials = val4.materials;
				foreach (Material val5 in materials)
				{
					if (!((Object)(object)val5 == (Object)null))
					{
						try
						{
							val5.SetFloat("_FresnelAmount", 1f);
							val5.SetFloat("_FresnelScale", 1f);
							val5.SetFloat("_FresnelPower", 5f);
							val5.SetFloat("_FresnelBias", 0f);
							val5.SetColor("_FresnelColor", color);
							val5.SetFloat("_FresnelEmission", 1f);
						}
						catch
						{
						}
					}
				}
			}
		}

		public static void SetHealthCurrent(EnemyHealth health, int value)
		{
			try
			{
				if (_healthCurrentField == null)
				{
					_healthCurrentField = typeof(EnemyHealth).GetField("healthCurrent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				_healthCurrentField?.SetValue(health, value);
			}
			catch
			{
			}
		}

		public static void BoostThrownImpact(PhysGrabObject obj, float multiplier, float time)
		{
			try
			{
				if (_impactDetectorField == null)
				{
					_impactDetectorField = typeof(PhysGrabObject).GetField("impactDetector", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				object obj2 = _impactDetectorField?.GetValue(obj);
				if (obj2 != null)
				{
					if (_hurtMultiplierMethod == null)
					{
						_hurtMultiplierMethod = obj2.GetType().GetMethod("PlayerHurtMultiplier", BindingFlags.Instance | BindingFlags.Public);
					}
					_hurtMultiplierMethod?.Invoke(obj2, new object[2] { multiplier, time });
				}
			}
			catch
			{
			}
		}

		public static bool TryGetSafeRandomPoint(Vector3 from, out Vector3 point)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: 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_0043: 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_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: 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_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			int mask = LayerMask.GetMask(new string[1] { "Default" });
			NavMeshHit val2 = default(NavMeshHit);
			RaycastHit val3 = default(RaycastHit);
			for (int i = 0; i < 16; i++)
			{
				LevelPoint val = SemiFunc.LevelPointGet(from, 0f, 9999f);
				if (!((Object)(object)val == (Object)null) && NavMesh.SamplePosition(((Component)val).transform.position + Random.insideUnitSphere * 3f, ref val2, 5f, -1) && Physics.Raycast(((NavMeshHit)(ref val2)).position + Vector3.up * 0.5f, Vector3.down, ref val3, 3f, mask, (QueryTriggerInteraction)1))
				{
					point = ((RaycastHit)(ref val3)).point + Vector3.up * 0.6f;
					return true;
				}
			}
			point = from;
			return false;
		}

		public static PhysGrabObject? GetPlayerPhysGrabObject(PlayerAvatar player)
		{
			try
			{
				if ((object)_tumbleField == null)
				{
					_tumbleField = typeof(PlayerAvatar).GetField("tumble", BindingFlags.Instance | BindingFlags.NonPublic);
				}
				object obj = _tumbleField?.GetValue(player);
				if (obj == null)
				{
					return null;
				}
				if ((object)_tumblePhysGrabObjectField == null)
				{
					_tumblePhysGrabObjectField = obj.GetType().GetField("physGrabObject", BindingFlags.Instance | BindingFlags.NonPublic);
				}
				object? obj2 = _tumblePhysGrabObjectField?.GetValue(obj);
				return (PhysGrabObject?)((obj2 is PhysGrabObject) ? obj2 : null);
			}
			catch
			{
				return null;
			}
		}

		public static void SetPlayerClientPosition(PlayerAvatar player, Vector3 pos)
		{
			//IL_0050: 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)
			try
			{
				if ((object)_clientPositionField == null)
				{
					_clientPositionField = typeof(PlayerAvatar).GetField("clientPosition", BindingFlags.Instance | BindingFlags.NonPublic);
				}
				if ((object)_clientPositionCurrentField == null)
				{
					_clientPositionCurrentField = typeof(PlayerAvatar).GetField("clientPositionCurrent", BindingFlags.Instance | BindingFlags.NonPublic);
				}
				_clientPositionField?.SetValue(player, pos);
				_clientPositionCurrentField?.SetValue(player, pos);
			}
			catch
			{
			}
		}

		public static void SetPlayerVisualPosition(PlayerAvatarVisuals visuals, Vector3 pos)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((object)_visualPositionField == null)
				{
					_visualPositionField = typeof(PlayerAvatarVisuals).GetField("visualPosition", BindingFlags.Instance | BindingFlags.NonPublic);
				}
				_visualPositionField?.SetValue(visuals, pos);
			}
			catch
			{
			}
		}

		public static bool IsPlayerDisabled(PlayerAvatar player)
		{
			try
			{
				if ((object)_isDisabledField == null)
				{
					_isDisabledField = typeof(PlayerAvatar).GetField("isDisabled", BindingFlags.Instance | BindingFlags.NonPublic);
				}
				return _isDisabledField != null && (bool)(_isDisabledField.GetValue(player) ?? ((object)false));
			}
			catch
			{
				return false;
			}
		}
	}
	public class BoomdayBoyFusion : MonoBehaviour
	{
		internal static readonly Color AuraColor = new Color(1f, 0.4f, 0f);

		private EnemyBirthdayBoy _birthday;

		private EnemyHealth? _health;

		private EnemyParent? _self;

		private Enemy? _enemy;

		private PhysGrabObject? _selfPhys;

		private bool _fuseLit;

		private bool _deathDetonated;

		private bool _hpDone;

		private float _fuseTimer;

		private float _explodeCooldown;

		private float _balloonTimer;

		private float _proximityTimer;

		private float _glowTimer;

		private readonly List<Vector3> _orderedKeys = new List<Vector3>();

		private readonly HashSet<Vector3> _seen = new HashSet<Vector3>();

		private void Awake()
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			_birthday = ((Component)this).GetComponent<EnemyBirthdayBoy>();
			_self = ((Component)this).GetComponentInParent<EnemyParent>();
			_health = ((Component)this).GetComponentInParent<EnemyHealth>() ?? ((Component)this).GetComponentInChildren<EnemyHealth>();
			_enemy = ((Component)this).GetComponent<Enemy>() ?? ((Component)this).GetComponentInParent<Enemy>();
			_selfPhys = ((Component)this).GetComponentInParent<PhysGrabObject>() ?? ((Component)this).GetComponentInChildren<PhysGrabObject>(true);
			if (SemiFunc.IsMasterClientOrSingleplayer() && (Object)(object)_health != (Object)null)
			{
				_health.health = Mathf.Max(1, Mathf.RoundToInt((float)_health.health * Plugin.MutationHealthMultiplier.Value));
			}
			FusionShared.ApplyMutationGlow(((Component)this).transform, AuraColor);
		}

		private void Update()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			_glowTimer -= Time.deltaTime;
			if (_glowTimer <= 0f)
			{
				_glowTimer = 2f;
				FusionShared.ApplyMutationGlow(((Component)this).transform, AuraColor);
			}
			_balloonTimer -= Time.deltaTime;
			if (_balloonTimer <= 0f)
			{
				_balloonTimer = 0.2f;
				SyncAndTintBalloons();
			}
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			EnsureHpDoubled();
			if (_deathDetonated || (Object)(object)_birthday == (Object)null)
			{
				return;
			}
			HostBalloonContacts();
			if (_explodeCooldown > 0f)
			{
				_explodeCooldown -= Time.deltaTime;
			}
			_proximityTimer -= Time.deltaTime;
			if (!_fuseLit && _explodeCooldown <= 0f && _proximityTimer <= 0f)
			{
				_proximityTimer = 0.25f;
				if (FusionShared.NearestPlayerWithin(((Component)this).transform.position, Plugin.BoomdayFuseRange.Value))
				{
					_fuseLit = true;
					_fuseTimer = Plugin.BoomdayFuseTime.Value;
				}
			}
			if (_fuseLit)
			{
				_fuseTimer -= Time.deltaTime;
				if (_fuseTimer <= 0f)
				{
					ProximityExplode();
				}
			}
		}

		private void EnsureHpDoubled()
		{
			if (!_hpDone && !((Object)(object)_health == (Object)null))
			{
				_hpDone = true;
				FusionShared.SetHealthCurrent(_health, _health.health);
			}
		}

		private void SyncAndTintBalloons()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_birthday == (Object)null || _birthday.balloons == null)
			{
				return;
			}
			foreach (KeyValuePair<Vector3, GameObject> balloon in _birthday.balloons)
			{
				if (!((Object)(object)balloon.Value == (Object)null) && _seen.Add(balloon.Key))
				{
					_orderedKeys.Add(balloon.Key);
					TintBalloon(balloon.Value);
				}
			}
		}

		private void HostBalloonContacts()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: 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_0111: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_birthday == (Object)null || _birthday.balloons == null || _orderedKeys.Count == 0)
			{
				return;
			}
			float value = Plugin.BoomdayBalloonTouchRadius.Value;
			List<Vector3> list = null;
			foreach (Vector3 orderedKey in _orderedKeys)
			{
				if (!_birthday.balloons.TryGetValue(orderedKey, out var value2) || (Object)(object)value2 == (Object)null)
				{
					(list ?? (list = new List<Vector3>())).Add(orderedKey);
					continue;
				}
				Vector3 position = value2.transform.position;
				if (AnyPlayerWithin(position, value))
				{
					ExplodeBalloon(value2, position);
					(list ?? (list = new List<Vector3>())).Add(orderedKey);
				}
				else if (AnyOtherEnemyWithin(position, value))
				{
					PopBalloon(value2, position);
					(list ?? (list = new List<Vector3>())).Add(orderedKey);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (Vector3 item in list)
			{
				ForgetBalloon(item);
			}
		}

		private static bool AnyPlayerWithin(Vector3 pos, float radius)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			foreach (PlayerAvatar item in FusionShared.AllPlayers())
			{
				if (!((Object)(object)item == (Object)null) && Vector3.Distance(pos, ((Component)item).transform.position) <= radius)
				{
					return true;
				}
			}
			return false;
		}

		private bool AnyOtherEnemyWithin(Vector3 pos, float radius)
		{
			//IL_0046: 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)
			EnemyDirector instance = EnemyDirector.instance;
			if ((Object)(object)instance == (Object)null || instance.enemiesSpawned == null)
			{
				return false;
			}
			foreach (EnemyParent item in instance.enemiesSpawned)
			{
				if (!((Object)(object)item == (Object)null) && !((Object)(object)item == (Object)(object)_self) && Vector3.Distance(pos, ((Component)item).transform.position) <= radius)
				{
					return true;
				}
			}
			return false;
		}

		private void ProximityExplode()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			FusionShared.ExplodeAuthoritative(((Component)this).transform.position, 1.3f, Plugin.BoomdayCoreDamage.Value, 0, _selfPhys, _enemy);
			AggroNearestPlayer();
			StartBalloonChain();
			_fuseLit = false;
			_explodeCooldown = Plugin.BoomdayExplodeCooldown.Value;
		}

		public void Detonate()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (!_deathDetonated)
			{
				_deathDetonated = true;
				FusionShared.ExplodeAuthoritative(((Component)this).transform.position, 1.6f, Plugin.BoomdayCoreDamage.Value, 0, _selfPhys, _enemy);
				StartBalloonChain();
			}
		}

		private void AggroNearestPlayer()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((Object)(object)_birthday == (Object)null))
				{
					PlayerAvatar val = FusionShared.NearestPlayer(((Component)this).transform.position, Plugin.BoomdayFuseRange.Value * 3f);
					if (!((Object)(object)val == (Object)null))
					{
						_birthday.playerTarget = val;
						_birthday.UpdateState((State)6);
					}
				}
			}
			catch
			{
			}
		}

		private void StartBalloonChain()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_birthday == (Object)null || _orderedKeys.Count == 0)
			{
				return;
			}
			List<GameObject> list = new List<GameObject>();
			foreach (Vector3 orderedKey in _orderedKeys)
			{
				if (_birthday.balloons != null && _birthday.balloons.TryGetValue(orderedKey, out var value) && (Object)(object)value != (Object)null)
				{
					list.Add(value);
					_birthday.balloons.Remove(orderedKey);
				}
			}
			_orderedKeys.Clear();
			_seen.Clear();
			Plugin.Instance.StartBalloonChain(list, Plugin.BoomdayBalloonDamage.Value, ((Object)(object)_birthday != (Object)null) ? _birthday.balloonPopEffect : null);
		}

		private void ForgetBalloon(Vector3 key)
		{
			//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)
			_birthday?.balloons?.Remove(key);
			_orderedKeys.Remove(key);
			_seen.Remove(key);
		}

		private void ExplodeBalloon(GameObject balloon, Vector3 bp)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			FusionShared.ExplodeAuthoritative(bp, 0.7f, Plugin.BoomdayBalloonDamage.Value, 0);
			if ((Object)(object)_birthday != (Object)null && (Object)(object)_birthday.balloonPopEffect != (Object)null)
			{
				Object.Instantiate<GameObject>(_birthday.balloonPopEffect, bp, Quaternion.identity);
			}
			Object.Destroy((Object)(object)balloon);
		}

		private void PopBalloon(GameObject balloon, Vector3 bp)
		{
			//IL_002c: 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)
			if ((Object)(object)_birthday != (Object)null && (Object)(object)_birthday.balloonPopEffect != (Object)null)
			{
				Object.Instantiate<GameObject>(_birthday.balloonPopEffect, bp, Quaternion.identity);
			}
			Object.Destroy((Object)(object)balloon);
		}

		private void TintBalloon(GameObject balloon)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			Renderer[] componentsInChildren = balloon.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null))
				{
					MaterialPropertyBlock val2 = new MaterialPropertyBlock();
					val.GetPropertyBlock(val2);
					val2.SetColor("_Color", new Color(1f, 0.45f, 0f));
					val2.SetColor("_EmissionColor", new Color(1f, 0.35f, 0f) * 1.5f);
					val.SetPropertyBlock(val2);
				}
			}
		}
	}
	public class PoltergeistFusion : MonoBehaviour
	{
		internal static readonly Color AuraColor = new Color(0.35f, 0.8f, 1f);

		private EnemyHealth? _health;

		private bool _hpDone;

		private float _throwCooldown;

		private float _playerFloatCooldown;

		private float _fieldTimer;

		private float _glowTimer;

		private GameObject? _fieldSphere;

		private void Awake()
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			_health = ((Component)this).GetComponentInParent<EnemyHealth>() ?? ((Component)this).GetComponentInChildren<EnemyHealth>();
			if (SemiFunc.IsMasterClientOrSingleplayer() && (Object)(object)_health != (Object)null)
			{
				_health.health = Mathf.Max(1, Mathf.RoundToInt((float)_health.health * Plugin.MutationHealthMultiplier.Value));
			}
			FusionShared.ApplyMutationGlow(((Component)this).transform, AuraColor);
			_throwCooldown = Plugin.PoltergeistThrowInterval.Value;
			_playerFloatCooldown = Plugin.PoltergeistPlayerFloatInterval.Value;
		}

		private void Update()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			_glowTimer -= Time.deltaTime;
			if (_glowTimer <= 0f)
			{
				_glowTimer = 2f;
				FusionShared.ApplyMutationGlow(((Component)this).transform, AuraColor);
			}
			EnsureFieldSphere();
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			EnsureHpDoubled();
			_fieldTimer -= Time.deltaTime;
			if (_fieldTimer <= 0f)
			{
				_fieldTimer = 0.25f;
				foreach (PhysGrabObject item in FusionShared.PhysObjectsInRadius(((Component)this).transform.position, Plugin.PoltergeistRange.Value))
				{
					if (!((Object)(object)item == (Object)null))
					{
						try
						{
							item.OverrideZeroGravity(0.35f);
							item.OverrideDrag(1f, 0.35f);
							item.OverrideAngularDrag(1.5f, 0.35f);
						}
						catch
						{
						}
					}
				}
			}
			_playerFloatCooldown -= Time.deltaTime;
			if (_playerFloatCooldown <= 0f)
			{
				_playerFloatCooldown = Plugin.PoltergeistPlayerFloatInterval.Value;
				foreach (PlayerAvatar item2 in FusionShared.PlayersInRadius(((Component)this).transform.position, Plugin.PoltergeistRange.Value))
				{
					if (!((Object)(object)item2 == (Object)null))
					{
						try
						{
							item2.ForceImpulse(Vector3.up * Plugin.PoltergeistPlayerFloatForce.Value);
						}
						catch
						{
						}
					}
				}
			}
			_throwCooldown -= Time.deltaTime;
			if (_throwCooldown <= 0f)
			{
				_throwCooldown = Plugin.PoltergeistThrowInterval.Value;
				ThrowValuableAtPlayer();
			}
		}

		private void EnsureHpDoubled()
		{
			if (!_hpDone && !((Object)(object)_health == (Object)null))
			{
				_hpDone = true;
				FusionShared.SetHealthCurrent(_health, _health.health);
			}
		}

		private void EnsureFieldSphere()
		{
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_fieldSphere != (Object)null)
			{
				return;
			}
			try
			{
				EnemyParent componentInParent = ((Component)this).GetComponentInParent<EnemyParent>();
				EnemyFloaterSphereEffect val = ((componentInParent != null) ? ((Component)componentInParent).GetComponentInChildren<EnemyFloaterSphereEffect>(true) : null) ?? ((Component)this).GetComponentInChildren<EnemyFloaterSphereEffect>(true);
				MeshRenderer val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<MeshRenderer>() : null);
				Material val3 = (((Object)(object)val2 != (Object)null) ? ((Renderer)val2).sharedMaterial : null);
				if (!((Object)(object)val3 == (Object)null))
				{
					GameObject val4 = GameObject.CreatePrimitive((PrimitiveType)0);
					((Object)val4).name = "MatsuPoltergeistField";
					Collider component = val4.GetComponent<Collider>();
					if ((Object)(object)component != (Object)null)
					{
						Object.Destroy((Object)(object)component);
					}
					MeshRenderer component2 = val4.GetComponent<MeshRenderer>();
					((Renderer)component2).sharedMaterial = val3;
					((Renderer)component2).shadowCastingMode = (ShadowCastingMode)0;
					((Renderer)component2).receiveShadows = false;
					val4.transform.SetParent(((Component)this).transform, false);
					val4.transform.localPosition = Vector3.zero;
					val4.transform.localScale = Vector3.one * (Plugin.PoltergeistRange.Value * 2f);
					_fieldSphere = val4;
				}
			}
			catch
			{
				_fieldSphere = null;
			}
		}

		private void ThrowValuableAtPlayer()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			PlayerAvatar val = FusionShared.NearestPlayer(((Component)this).transform.position, Plugin.PoltergeistRange.Value * 1.5f);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			PhysGrabObject val2 = null;
			float num = float.MaxValue;
			foreach (PhysGrabObject item in FusionShared.PhysObjectsInRadius(((Component)this).transform.position, Plugin.PoltergeistRange.Value))
			{
				if (!((Object)(object)item == (Object)null) && !((Object)(object)item.rb == (Object)null) && !((Object)(object)((Component)item).GetComponentInParent<ValuableObject>() == (Object)null))
				{
					float num2 = Vector3.Distance(((Component)this).transform.position, ((Component)item).transform.position);
					if (num2 < num)
					{
						num = num2;
						val2 = item;
					}
				}
			}
			if ((Object)(object)val2 == (Object)null || (Object)(object)val2.rb == (Object)null)
			{
				return;
			}
			Rigidbody rb = val2.rb;
			EnemyParent componentInParent = ((Component)this).GetComponentInParent<EnemyParent>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				Collider[] componentsInChildren = ((Component)componentInParent).GetComponentsInChildren<Collider>(true);
				Collider[] componentsInChildren2 = ((Component)val2).GetComponentsInChildren<Collider>(true);
				Collider[] array = componentsInChildren;
				foreach (Collider val3 in array)
				{
					if ((Object)(object)val3 == (Object)null)
					{
						continue;
					}
					Collider[] array2 = componentsInChildren2;
					foreach (Collider val4 in array2)
					{
						if ((Object)(object)val4 != (Object)null)
						{
							try
							{
								Physics.IgnoreCollision(val3, val4, true);
							}
							catch
							{
							}
						}
					}
				}
			}
			try
			{
				val2.ResetMass();
			}
			catch
			{
			}
			float num3 = Mathf.Min(20f * rb.mass, 100f);
			try
			{
				val2.ResetIndestructible();
			}
			catch
			{
			}
			Vector3 val5 = ((Component)val).transform.position + Vector3.up * 1f;
			Vector3 val6 = Vector3.Lerp(((Component)this).transform.forward, val5 - val2.centerPoint, 0.5f);
			rb.AddForce(val6 * num3, (ForceMode)1);
			rb.AddTorque(((Component)val2).transform.right * 0.5f, (ForceMode)1);
			FusionShared.BoostThrownImpact(val2, 5f, 2f);
		}
	}
	public class CleanupCrewFusion : MonoBehaviour
	{
		internal static readonly Color AuraColor = new Color(0.4f, 1f, 0.15f);

		private static FieldInfo? _headStateField;

		private EnemyBombThrower _thrower;

		private EnemyHealth? _health;

		private bool _hpDone;

		private float _glowTimer;

		private int _prevHeadState = -1;

		private void Awake()
		{
			_thrower = ((Component)this).GetComponent<EnemyBombThrower>();
			_health = ((Component)this).GetComponentInParent<EnemyHealth>() ?? ((Component)this).GetComponentInChildren<EnemyHealth>();
			if (SemiFunc.IsMasterClientOrSingleplayer() && (Object)(object)_health != (Object)null)
			{
				_health.health = Mathf.Max(1, Mathf.RoundToInt((float)_health.health * Plugin.MutationHealthMultiplier.Value));
			}
			ApplyGlow();
			Plugin.GetMeltdownHeadPrefabRef();
		}

		private void Update()
		{
			_glowTimer -= Time.deltaTime;
			if (_glowTimer <= 0f)
			{
				_glowTimer = 2f;
				ApplyGlow();
			}
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			EnsureHpDoubled();
			if (!((Object)(object)_thrower == (Object)null) && !((Object)(object)_thrower.head == (Object)null))
			{
				int num = ReadHeadState(_thrower.head);
				if (_prevHeadState != -1 && num == 1 && _prevHeadState != 1)
				{
					SpawnExtraHeads();
				}
				_prevHeadState = num;
			}
		}

		private void SpawnExtraHeads()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			Transform headSpawnTransform = _thrower.headSpawnTransform;
			if ((Object)(object)headSpawnTransform == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[MeltdownCrew] headSpawnTransform is null; can't spawn extras.");
				return;
			}
			Plugin.Log.LogInfo((object)"[MeltdownCrew] body launched its head — spawning 2 extra heads.");
			Plugin.SpawnMeltdownHead(headSpawnTransform.position, headSpawnTransform.rotation, headSpawnTransform.forward, Plugin.MeltdownSlowSpeed.Value);
			Plugin.SpawnMeltdownHead(headSpawnTransform.position, headSpawnTransform.rotation, headSpawnTransform.forward, Plugin.MeltdownFastSpeed.Value);
		}

		private void EnsureHpDoubled()
		{
			if (!_hpDone && !((Object)(object)_health == (Object)null))
			{
				_hpDone = true;
				FusionShared.SetHealthCurrent(_health, _health.health);
			}
		}

		private void ApplyGlow()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			FusionShared.ApplyMutationGlow(((Component)this).transform, AuraColor);
			if ((Object)(object)_thrower != (Object)null && (Object)(object)_thrower.head != (Object)null)
			{
				FusionShared.ApplyMutationGlow(((Component)_thrower.head).transform, AuraColor);
			}
		}

		private static int ReadHeadState(EnemyBombThrowerHead head)
		{
			try
			{
				if (_headStateField == null)
				{
					_headStateField = typeof(EnemyBombThrowerHead).GetField("currentState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				object obj = _headStateField?.GetValue(head);
				return (obj != null) ? Convert.ToInt32(obj) : (-1);
			}
			catch
			{
				return -1;
			}
		}
	}
	public class MeltdownExtraHead : MonoBehaviour
	{
		private PhotonView? _pv;

		private Rigidbody? _rb;

		private ParticleScriptExplosion? _explosion;

		private float _factor = 1f;

		private bool _launched;

		private bool _exploding;

		private float _flightTimer;

		private float _destroyTimer;

		private void Awake()
		{
			_pv = ((Component)this).GetComponent<PhotonView>();
			_rb = ((Component)this).GetComponent<PhysGrabObject>()?.rb ?? ((Component)this).GetComponent<Rigidbody>();
			_explosion = ((Component)this).GetComponent<ParticleScriptExplosion>();
			Animator component = ((Component)this).GetComponent<Animator>();
			if ((Object)(object)component != (Object)null)
			{
				((Behaviour)component).enabled = false;
			}
		}

		public void Launch(float factor, Vector3 forward)
		{
			//IL_003a: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			_factor = factor;
			_flightTimer = Plugin.MeltdownHeadFlightSeconds.Value;
			_launched = true;
			if ((Object)(object)_rb != (Object)null)
			{
				_rb.isKinematic = false;
				Vector3 val = Vector3.Lerp(((Vector3)(ref forward)).normalized, Vector3.up, 0.3f);
				_rb.AddForce(val * 20f, (ForceMode)1);
				_rb.AddTorque(Vector3.right * 0.25f, (ForceMode)1);
			}
		}

		private void FixedUpdate()
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: 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)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			if (_exploding)
			{
				_destroyTimer -= Time.fixedDeltaTime;
				if (_destroyTimer <= 0f)
				{
					DestroySelf();
				}
			}
			else
			{
				if (!_launched || (Object)(object)_rb == (Object)null)
				{
					return;
				}
				PlayerAvatar val = FusionShared.NearestPlayer(_rb.position, 40f);
				if ((Object)(object)val != (Object)null)
				{
					Vector3 val2 = ((Component)val).transform.position - _rb.position;
					val2.y = 0f;
					if (((Vector3)(ref val2)).sqrMagnitude > 0.01f)
					{
						_rb.AddForce(((Vector3)(ref val2)).normalized * Plugin.MeltdownHomingForce.Value * Mathf.Max(0.5f, _factor), (ForceMode)0);
					}
				}
				float num = Plugin.MeltdownBaseSpeed.Value * _factor;
				Vector3 velocity = _rb.velocity;
				Vector3 val3 = default(Vector3);
				((Vector3)(ref val3))..ctor(velocity.x, 0f, velocity.z);
				if (((Vector3)(ref val3)).magnitude > num)
				{
					val3 = ((Vector3)(ref val3)).normalized * num;
					_rb.velocity = new Vector3(val3.x, velocity.y, val3.z);
				}
				_flightTimer -= Time.fixedDeltaTime;
				if (_flightTimer <= 0f)
				{
					_exploding = true;
					_destroyTimer = 0.3f;
					if (SemiFunc.IsMultiplayer() && (Object)(object)_pv != (Object)null)
					{
						_pv.RPC("ExplodeRPC", (RpcTarget)0, new object[1] { _rb.position });
					}
					else
					{
						ExplodeRPC(_rb.position);
					}
				}
			}
		}

		[PunRPC]
		private void ExplodeRPC(Vector3 pos)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				ParticleScriptExplosion? explosion = _explosion;
				if (explosion != null)
				{
					explosion.Spawn(pos, 2f, Plugin.MeltdownHeadDamage.Value, 30, 4f, false, false, 1f);
				}
			}
			catch
			{
			}
			Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].enabled = false;
			}
		}

		private void DestroySelf()
		{
			try
			{
				if (SemiFunc.IsMultiplayer() && (Object)(object)_pv != (Object)null && _pv.IsMine)
				{
					PhotonNetwork.Destroy(((Component)this).gameObject);
				}
				else
				{
					Object.Destroy((Object)(object)((Component)this).gameObject);
				}
			}
			catch
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}
	public class PlayerTeleportHelper : MonoBehaviour
	{
		private PhotonView? _pv;

		private PlayerAvatar? _avatar;

		private void Awake()
		{
			_pv = ((Component)this).GetComponent<PhotonView>();
			_avatar = ((Component)this).GetComponent<PlayerAvatar>();
		}

		public static void Trigger(PlayerAvatar player, Vector3 pos, int damage, int enemyIndex)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			PlayerTeleportHelper component = ((Component)player).GetComponent<PlayerTeleportHelper>();
			if (!((Object)(object)component == (Object)null) && !((Object)(object)component._pv == (Object)null))
			{
				if (SemiFunc.IsMultiplayer())
				{
					component._pv.RPC("TeleportAndHurtRPC", (RpcTarget)0, new object[3] { pos, damage, enemyIndex });
				}
				else
				{
					component.TeleportAndHurtRPC(pos, damage, enemyIndex);
				}
			}
		}

		[PunRPC]
		private void TeleportAndHurtRPC(Vector3 pos, int damage, int enemyIndex)
		{
			//IL_007f: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)_avatar == (Object)null)
				{
					return;
				}
				if (SemiFunc.IsMasterClientOrSingleplayer())
				{
					PhysGrabObject playerPhysGrabObject = FusionShared.GetPlayerPhysGrabObject(_avatar);
					if ((Object)(object)playerPhysGrabObject != (Object)null)
					{
						playerPhysGrabObject.Teleport(pos, ((Component)_avatar).transform.rotation);
						if ((Object)(object)playerPhysGrabObject.rb != (Object)null)
						{
							playerPhysGrabObject.rb.velocity = Vector3.zero;
							playerPhysGrabObject.rb.angularVelocity = Vector3.zero;
						}
					}
				}
				((Component)_avatar).transform.position = pos;
				FusionShared.SetPlayerClientPosition(_avatar, pos);
				if ((Object)(object)_avatar.playerAvatarVisuals != (Object)null)
				{
					((Component)_avatar.playerAvatarVisuals).transform.position = pos;
					FusionShared.SetPlayerVisualPosition(_avatar.playerAvatarVisuals, pos);
				}
				if (SemiFunc.IsMasterClientOrSingleplayer())
				{
					_avatar.playerHealth.HurtOther(damage, pos, false, enemyIndex, false);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Snatcher] teleport RPC error: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(PlayerAvatar), "Start")]
	internal static class PlayerAvatar_Start_Patch
	{
		private static void Postfix(PlayerAvatar __instance)
		{
			try
			{
				if ((Object)(object)__instance != (Object)null && (Object)(object)((Component)__instance).GetComponent<PlayerTeleportHelper>() == (Object)null)
				{
					((Component)__instance).gameObject.AddComponent<PlayerTeleportHelper>();
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Snatcher] PlayerAvatar_Start_Patch error: {arg}");
			}
		}
	}
	public class SnatcherFusion : MonoBehaviour
	{
		internal static readonly Color AuraColor = new Color(0.6f, 0f, 0.85f);

		private static FieldInfo? _playerTargetField;

		private EnemyHidden _hidden;

		private EnemyParent? _self;

		private EnemyHealth? _health;

		private bool _hpDone;

		private float _glowTimer;

		private State _prevState;

		private bool _stateInitialized;

		private void Awake()
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			_hidden = ((Component)this).GetComponent<EnemyHidden>();
			_self = ((Component)this).GetComponentInParent<EnemyParent>();
			_health = ((Component)this).GetComponentInParent<EnemyHealth>() ?? ((Component)this).GetComponentInChildren<EnemyHealth>();
			if (SemiFunc.IsMasterClientOrSingleplayer() && (Object)(object)_health != (Object)null)
			{
				_health.health = Mathf.Max(1, Mathf.RoundToInt((float)_health.health * Plugin.MutationHealthMultiplier.Value));
			}
			FusionShared.ApplyMutationGlow(((Component)this).transform, AuraColor);
		}

		private void Update()
		{
			//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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Invalid comparison between Unknown and I4
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			_glowTimer -= Time.deltaTime;
			if (_glowTimer <= 0f)
			{
				_glowTimer = 2f;
				FusionShared.ApplyMutationGlow(((Component)this).transform, AuraColor);
			}
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			EnsureHpDoubled();
			if ((Object)(object)_hidden == (Object)null)
			{
				return;
			}
			State currentState = _hidden.currentState;
			if (!_stateInitialized)
			{
				_prevState = currentState;
				_stateInitialized = true;
			}
			else
			{
				if (currentState == _prevState)
				{
					return;
				}
				if ((int)currentState == 7)
				{
					PlayerAvatar playerTarget = GetPlayerTarget(_hidden);
					if ((Object)(object)playerTarget != (Object)null && !FusionShared.IsPlayerDisabled(playerTarget) && FusionShared.TryGetSafeRandomPoint(((Component)playerTarget).transform.position, out var point))
					{
						int enemyIndex = (((Object)(object)_self != (Object)null && (Object)(object)EnemyDirector.instance != (Object)null) ? EnemyDirector.instance.enemiesSpawned.IndexOf(_self) : (-1));
						PlayerTeleportHelper.Trigger(playerTarget, point, Plugin.SnatcherDamage.Value, enemyIndex);
						Plugin.Log.LogInfo((object)"[Snatcher] Snatched a player to a random spot.");
					}
				}
				_prevState = currentState;
			}
		}

		private void EnsureHpDoubled()
		{
			if (!_hpDone && !((Object)(object)_health == (Object)null))
			{
				_hpDone = true;
				FusionShared.SetHealthCurrent(_health, _health.health);
			}
		}

		private static PlayerAvatar? GetPlayerTarget(EnemyHidden hidden)
		{
			try
			{
				if ((object)_playerTargetField == null)
				{
					_playerTargetField = typeof(EnemyHidden).GetField("playerTarget", BindingFlags.Instance | BindingFlags.NonPublic);
				}
				object? obj = _playerTargetField?.GetValue(hidden);
				return (PlayerAvatar?)((obj is PlayerAvatar) ? obj : null);
			}
			catch
			{
				return null;
			}
		}
	}
	public class PeeperFusion : MonoBehaviour
	{
		internal static readonly Color AuraColor = new Color(1f, 0.1f, 0.1f);

		private static FieldInfo? _targetPlayerField;

		private EnemyCeilingEye _eye;

		private EnemyHealth? _health;

		private bool _hpDone;

		private float _glowTimer;

		private PlayerAvatar? _lastTarget;

		private float _stareTimer;

		private void Awake()
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			_eye = ((Component)this).GetComponent<EnemyCeilingEye>();
			_health = ((Component)this).GetComponentInParent<EnemyHealth>() ?? ((Component)this).GetComponentInChildren<EnemyHealth>();
			if (SemiFunc.IsMasterClientOrSingleplayer() && (Object)(object)_health != (Object)null)
			{
				_health.health = Mathf.Max(1, Mathf.RoundToInt((float)_health.health * Plugin.MutationHealthMultiplier.Value));
			}
			FusionShared.ApplyMutationGlow(((Component)this).transform, AuraColor);
		}

		private void Update()
		{
			//IL_0030: 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_005b: Invalid comparison between Unknown and I4
			_glowTimer -= Time.deltaTime;
			if (_glowTimer <= 0f)
			{
				_glowTimer = 2f;
				FusionShared.ApplyMutationGlow(((Component)this).transform, AuraColor);
			}
			EnsureHpDoubled();
			if ((Object)(object)_eye == (Object)null)
			{
				return;
			}
			PlayerAvatar val = (((int)_eye.currentState == 3) ? GetTarget(_eye) : null);
			if ((Object)(object)val == (Object)null)
			{
				_lastTarget = null;
				_stareTimer = 0f;
				return;
			}
			if ((Object)(object)val != (Object)(object)_lastTarget)
			{
				_lastTarget = val;
				_stareTimer = 0f;
			}
			_stareTimer += Time.deltaTime;
			if (_stareTimer >= Plugin.DeathgazeStareSeconds.Value)
			{
				_stareTimer = 0f;
				FireBeam(val);
			}
		}

		private void EnsureHpDoubled()
		{
			if (!_hpDone && !((Object)(object)_health == (Object)null) && SemiFunc.IsMasterClientOrSingleplayer())
			{
				_hpDone = true;
				FusionShared.SetHealthCurrent(_health, _health.health);
			}
		}

		private void FireBeam(PlayerAvatar target)
		{
			try
			{
				SemiLaser clownLaserPrefab = Plugin.GetClownLaserPrefab();
				if ((Object)(object)clownLaserPrefab == (Object)null)
				{
					return;
				}
				Transform source = (((Object)(object)_eye.eyeTransform != (Object)null) ? _eye.eyeTransform : ((Component)this).transform);
				GameObject val = Object.Instantiate<GameObject>(((Component)clownLaserPrefab).gameObject);
				val.SetActive(true);
				SemiLaser component = val.GetComponent<SemiLaser>();
				if ((Object)(object)component == (Object)null)
				{
					Object.Destroy((Object)(object)val);
					return;
				}
				HurtCollider componentInChildren = val.GetComponentInChildren<HurtCollider>(true);
				if ((Object)(object)componentInChildren != (Object)null)
				{
					componentInChildren.enemyHost = ((Component)_eye).GetComponent<Enemy>();
					componentInChildren.playerKill = false;
					componentInChildren.playerDamage = Plugin.DeathgazeBeamDamage.Value;
					componentInChildren.playerDamageCooldown = Plugin.DeathgazeBeamSeconds.Value + 1f;
				}
				EnemyParent componentInParent = ((Component)_eye).GetComponentInParent<EnemyParent>();
				Transform ignoreRoot = ((componentInParent != null) ? ((Component)componentInParent).transform : null) ?? ((Component)this).transform;
				val.AddComponent<PeeperBeam>().Init(component, source, target, Plugin.DeathgazeBeamSeconds.Value, ignoreRoot);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Deathgaze] fire error: {arg}");
			}
		}

		private static PlayerAvatar? GetTarget(EnemyCeilingEye eye)
		{
			try
			{
				if ((object)_targetPlayerField == null)
				{
					_targetPlayerField = typeof(EnemyCeilingEye).GetField("targetPlayer", BindingFlags.Instance | BindingFlags.NonPublic);
				}
				object? obj = _targetPlayerField?.GetValue(eye);
				return (PlayerAvatar?)((obj is PlayerAvatar) ? obj : null);
			}
			catch
			{
				return null;
			}
		}
	}
	public class PeeperBeam : MonoBehaviour
	{
		private static readonly int DefaultMask = LayerMask.GetMask(new string[1] { "Default" });

		private SemiLaser _laser;

		private Transform _source;

		private PlayerAvatar? _target;

		private float _duration;

		private float _elapsed;

		private Transform? _ignoreRoot;

		public void Init(SemiLaser laser, Transform source, PlayerAvatar target, float duration, Transform? ignoreRoot)
		{
			_laser = laser;
			_source = source;
			_target = target;
			_duration = duration;
			_ignoreRoot = ignoreRoot;
		}

		private void LateUpdate()
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			_elapsed += Time.deltaTime;
			if ((Object)(object)_laser == (Object)null || (Object)(object)_source == (Object)null || (Object)(object)_target == (Object)null || _elapsed >= _duration)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			Vector3 position = _source.position;
			Vector3 val = ((Component)_target).transform.position + Vector3.up * 1f;
			Vector3 val2 = val - position;
			float magnitude = ((Vector3)(ref val2)).magnitude;
			if (magnitude < 0.01f)
			{
				return;
			}
			val2 /= magnitude;
			Vector3 val3 = val;
			float num = magnitude;
			RaycastHit[] array = Physics.RaycastAll(position, val2, magnitude, DefaultMask, (QueryTriggerInteraction)1);
			for (int i = 0; i < array.Length; i++)
			{
				RaycastHit val4 = array[i];
				if (!((Object)(object)((RaycastHit)(ref val4)).collider == (Object)null) && (!((Object)(object)_ignoreRoot != (Object)null) || !((Component)((RaycastHit)(ref val4)).collider).transform.IsChildOf(_ignoreRoot)) && ((RaycastHit)(ref val4)).distance < num)
				{
					num = ((RaycastHit)(ref val4)).distance;
					val3 = ((RaycastHit)(ref val4)).point;
				}
			}
			_laser.LaserActive(position, val3, true);
		}
	}
	[BepInPlugin("com.matsu.repomutations", "REPO Mutant Enemies", "0.8.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.matsu.repomutations";

		public const string Name = "REPO Mutant Enemies";

		public const string Version = "0.8.0";

		public static ConfigEntry<float> MutationChancePerLevel;

		public static ConfigEntry<float> MutationMaxChance;

		public static ConfigEntry<float> MutationHealthMultiplier;

		public static ConfigEntry<float> MutationAuraRange;

		public static ConfigEntry<float> MutationAuraIntensity;

		public static ConfigEntry<float> BoomdayFuseRange;

		public static ConfigEntry<float> BoomdayFuseTime;

		public static ConfigEntry<float> BoomdayExplodeCooldown;

		public static ConfigEntry<int> BoomdayCoreDamage;

		public static ConfigEntry<int> BoomdayBalloonDamage;

		public static ConfigEntry<float> BoomdayBalloonTouchRadius;

		public static ConfigEntry<float> PoltergeistRange;

		public static ConfigEntry<float> PoltergeistPlayerFloatInterval;

		public static ConfigEntry<float> PoltergeistPlayerFloatForce;

		public static ConfigEntry<float> PoltergeistThrowInterval;

		public static ConfigEntry<float> MeltdownSlowSpeed;

		public static ConfigEntry<float> MeltdownFastSpeed;

		public static ConfigEntry<float> MeltdownBaseSpeed;

		public static ConfigEntry<float> MeltdownHomingForce;

		public static ConfigEntry<float> MeltdownHeadFlightSeconds;

		public static ConfigEntry<int> MeltdownHeadDamage;

		public static ConfigEntry<int> SnatcherDamage;

		public static ConfigEntry<float> DeathgazeStareSeconds;

		public static ConfigEntry<float> DeathgazeBeamSeconds;

		public static ConfigEntry<int> DeathgazeBeamDamage;

		public static ConfigEntry<KeyCode> DebugSpawnBoomdayKey;

		public static ConfigEntry<KeyCode> DebugSpawnPoltergeistKey;

		public static ConfigEntry<KeyCode> DebugSpawnMeltdownKey;

		public static ConfigEntry<KeyCode> DebugSpawnSnatcherKey;

		public static ConfigEntry<KeyCode> DebugSpawnDeathgazeKey;

		internal static float ForceFuseUntil;

		private Harmony _harmony;

		private static SemiLaser? _clownLaserPrefab;

		private static bool _clownLaserSearched;

		private const string MeltdownHeadPrefabId = "Matsu/MeltdownExtraHead";

		private static PrefabRef? _meltdownHeadRef;

		private static bool _meltdownHeadBuilt;

		public static Plugin Instance { get; private set; }

		public static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_0440: Unknown result type (might be due to invalid IL or missing references)
			//IL_044a: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			MutationChancePerLevel = ((BaseUnityPlugin)this).Config.Bind<float>("Mutation", "ChancePerLevel", 0.01f, "Base mutation chance per level (per mutation type). Chance = level x this + pity, where pity grows by (level x this) for every level that type failed to mutate, and resets to 0 once it does.");
			MutationMaxChance = ((BaseUnityPlugin)this).Config.Bind<float>("Mutation", "MaxChance", 1f, "Upper cap (0..1) for the level-scaled + pity mutation chance.");
			MutationHealthMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Mutation", "HealthMultiplier", 2f, "Health multiplier applied to every mutated enemy.");
			MutationAuraRange = ((BaseUnityPlugin)this).Config.Bind<float>("Mutation", "AuraLightRange", 4f, "Range of the coloured aura light attached to every mutated enemy (works even on invisible enemies).");
			MutationAuraIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("Mutation", "AuraLightIntensity", 3f, "Brightness of the coloured aura light.");
			BoomdayFuseRange = ((BaseUnityPlugin)this).Config.Bind<float>("BoomdayBoy", "FuseRange", 4f, "Player distance that lights the fuse.");
			BoomdayFuseTime = ((BaseUnityPlugin)this).Config.Bind<float>("BoomdayBoy", "FuseTime", 2.5f, "Seconds from fuse lit to an explosion.");
			BoomdayExplodeCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("BoomdayBoy", "ExplodeCooldown", 4f, "Seconds before a Boomday Boy can explode again. It survives its own blasts (recurring threat).");
			BoomdayCoreDamage = ((BaseUnityPlugin)this).Config.Bind<int>("BoomdayBoy", "CoreDamage", 40, "Explosion damage (proximity & death blasts). Uses the game's real explosion.");
			BoomdayBalloonDamage = ((BaseUnityPlugin)this).Config.Bind<int>("BoomdayBoy", "BalloonDamage", 20, "Per-balloon explosion damage. Uses the game's real explosion.");
			BoomdayBalloonTouchRadius = ((BaseUnityPlugin)this).Config.Bind<float>("BoomdayBoy", "BalloonTouchRadius", 1.3f, "A balloon explodes when a player comes this close to it (enemies only pop it, no explosion).");
			PoltergeistRange = ((BaseUnityPlugin)this).Config.Bind<float>("Poltergeist", "Range", 7.2f, "Radius of the zero-G field and telekinetic reach.");
			PoltergeistPlayerFloatInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Poltergeist", "PlayerFloatInterval", 1.4f, "Seconds between the light upward nudges that keep players unsteady in the field.");
			PoltergeistPlayerFloatForce = ((BaseUnityPlugin)this).Config.Bind<float>("Poltergeist", "PlayerFloatForce", 6f, "Strength of the periodic upward nudge on players inside the field.");
			PoltergeistThrowInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Poltergeist", "ThrowInterval", 2.2f, "Seconds between telekinetic throws. The thrown valuable's own physics impact deals damage (like the Rugrat).");
			MeltdownSlowSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("MeltdownCrew", "SlowHeadSpeed", 0.5f, "Speed factor of the sluggish 2nd head in the volley (1 = normal Cleanup Crew head speed).");
			MeltdownFastSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("MeltdownCrew", "FastHeadSpeed", 2f, "Speed factor of the frantic 3rd head in the volley (1 = normal Cleanup Crew head speed).");
			MeltdownBaseSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("MeltdownCrew", "BaseHeadSpeed", 4f, "Reference horizontal head speed (m/s) that the slow/fast factors scale. The head's speed is capped at this x factor.");
			MeltdownHomingForce = ((BaseUnityPlugin)this).Config.Bind<float>("MeltdownCrew", "FastHeadHomingForce", 12f, "Extra homing force applied to the fast head per (factor-1) so it actually reaches its higher speed and tracks the player.");
			MeltdownHeadFlightSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("MeltdownCrew", "HeadFlightSeconds", 7f, "How long each of the two EXTRA heads chases before it detonates. Set to roughly match the vanilla head's own fuse (~7s) so all three explode together — only their movement SPEED differs (0.5x / 2x).");
			MeltdownHeadDamage = ((BaseUnityPlugin)this).Config.Bind<int>("MeltdownCrew", "ExtraHeadDamage", 75, "Explosion damage of each extra head (matches the vanilla Cleanup Crew head by default).");
			SnatcherDamage = ((BaseUnityPlugin)this).Config.Bind<int>("Snatcher", "Damage", 20, "Damage dealt the instant a Snatcher (mutated Hidden) whisks you away.");
			DeathgazeStareSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Deathgaze", "StareSeconds", 7.5f, "Seconds a Deathgaze (mutated Peeper) must hold a player in its stare before it fires a beam.");
			DeathgazeBeamSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Deathgaze", "BeamSeconds", 2f, "How long each fired beam lasts.");
			DeathgazeBeamDamage = ((BaseUnityPlugin)this).Config.Bind<int>("Deathgaze", "BeamDamage", 35, "Damage the beam deals (at most once per beam).");
			DebugSpawnBoomdayKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Debug", "SpawnBoomdayKey", (KeyCode)290, "Press (host only) to spawn a Boomday Boy in front of your camera.");
			DebugSpawnPoltergeistKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Debug", "SpawnPoltergeistKey", (KeyCode)291, "Press (host only) to spawn a Poltergeist (mutated Mentalist) in front of your camera.");
			DebugSpawnMeltdownKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Debug", "SpawnMeltdownKey", (KeyCode)289, "Press (host only) to spawn a Meltdown Crew (mutated Cleanup Crew) in front of your camera.");
			DebugSpawnSnatcherKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Debug", "SpawnSnatcherKey", (KeyCode)288, "Press (host only) to spawn a Snatcher (mutated Hidden) in front of your camera.");
			DebugSpawnDeathgazeKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Debug", "SpawnDeathgazeKey", (KeyCode)287, "Press (host only) to spawn a Deathgaze (mutated Peeper) in front of your camera.");
			_harmony = new Harmony("com.matsu.repomutations");
			_harmony.PatchAll();
			Log.LogInfo((object)string.Format("{0} {1} loaded. Mutation chance = level x {2:P0} + pity. Debug: Boomday Boy (F9), Poltergeist (F10), Meltdown Crew (F8), Snatcher (F7), Deathgaze (F6). Everyone in the lobby must install this mod.", "REPO Mutant Enemies", "0.8.0", MutationChancePerLevel.Value));
		}

		private void Update()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown(DebugSpawnBoomdayKey.Value))
			{
				DebugSpawn("Birthday", typeof(EnemyBirthdayBoy), "Boomday Boy");
			}
			if (Input.GetKeyDown(DebugSpawnPoltergeistKey.Value))
			{
				DebugSpawn("Floater", typeof(EnemyFloater), "Poltergeist");
			}
			if (Input.GetKeyDown(DebugSpawnMeltdownKey.Value))
			{
				DebugSpawn("Bomb", typeof(EnemyBombThrower), "Meltdown Crew");
			}
			if (Input.GetKeyDown(DebugSpawnSnatcherKey.Value))
			{
				DebugSpawn("Hidden", typeof(EnemyHidden), "Snatcher");
			}
			if (Input.GetKeyDown(DebugSpawnDeathgazeKey.Value))
			{
				DebugSpawn("Peeper", typeof(EnemyCeilingEye), "Deathgaze");
			}
		}

		private static void DebugSpawn(string nameContains, Type componentType, string label)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!SemiFunc.IsMasterClientOrSingleplayer())
				{
					Log.LogWarning((object)"[Debug] Spawn is host-only.");
					return;
				}
				Camera main = Camera.main;
				if ((Object)(object)main == (Object)null)
				{
					Log.LogWarning((object)"[Debug] No main camera; are you in a level?");
					return;
				}
				Vector3 val = ((Component)main).transform.position + ((Component)main).transform.forward * 3f;
				EnemySetup val2 = FindEnemySetup(nameContains, componentType);
				if ((Object)(object)val2 == (Object)null)
				{
					Log.LogWarning((object)("[Debug] " + label + " base enemy setup not found."));
					return;
				}
				ForceFuseUntil = Time.time + 5f;
				Enemies.SpawnEnemy(val2, val, Quaternion.identity, false);
				Log.LogInfo((object)$"[Debug] Spawned a {label} at {val}.");
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"[Debug] spawn error: {arg}");
			}
		}

		private static EnemySetup? FindEnemySetup(string nameContains, Type componentType)
		{
			foreach (EnemySetup allEnemy in Enemies.AllEnemies)
			{
				if ((Object)(object)allEnemy != (Object)null && ((Object)allEnemy).name.IndexOf(nameContains, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return allEnemy;
				}
			}
			foreach (EnemySetup allEnemy2 in Enemies.AllEnemies)
			{
				if (allEnemy2?.spawnObjects == null)
				{
					continue;
				}
				foreach (PrefabRef spawnObject in allEnemy2.spawnObjects)
				{
					GameObject val = ((PrefabRef<GameObject>)(object)spawnObject)?.Prefab;
					if ((Object)(object)val != (Object)null && (Object)(object)val.GetComponentInChildren(componentType, true) != (Object)null)
					{
						return allEnemy2;
					}
				}
			}
			return null;
		}

		public static SemiLaser? GetClownLaserPrefab()
		{
			if (_clownLaserSearched)
			{
				return _clownLaserPrefab;
			}
			_clownLaserSearched = true;
			try
			{
				EnemySetup val = FindEnemySetup("Beamer", typeof(EnemyBeamer));
				if (val?.spawnObjects != null)
				{
					foreach (PrefabRef spawnObject in val.spawnObjects)
					{
						GameObject val2 = ((PrefabRef<GameObject>)(object)spawnObject)?.Prefab;
						EnemyBeamer val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponentInChildren<EnemyBeamer>(true) : null);
						if ((Object)(object)val3 != (Object)null && (Object)(object)val3.laser != (Object)null)
						{
							_clownLaserPrefab = val3.laser;
							break;
						}
					}
				}
				if ((Object)(object)_clownLaserPrefab == (Object)null)
				{
					Log.LogWarning((object)"[Deathgaze] Could not find the Clown/Beamer laser prefab; beams disabled.");
				}
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"[Deathgaze] laser prefab lookup error: {arg}");
			}
			return _clownLaserPrefab;
		}

		public static PrefabRef? GetMeltdownHeadPrefabRef()
		{
			if (_meltdownHeadBuilt)
			{
				return _meltdownHeadRef;
			}
			PrefabRef meltdownHeadRef = default(PrefabRef);
			if (NetworkPrefabs.TryGetNetworkPrefabRef("Matsu/MeltdownExtraHead", ref meltdownHeadRef))
			{
				_meltdownHeadBuilt = true;
				_meltdownHeadRef = meltdownHeadRef;
				return _meltdownHeadRef;
			}
			_meltdownHeadBuilt = true;
			try
			{
				EnemySetup val = FindEnemySetup("Bomb", typeof(EnemyBombThrower));
				GameObject val2 = null;
				if (val?.spawnObjects != null)
				{
					foreach (PrefabRef spawnObject in val.spawnObjects)
					{
						GameObject val3 = ((PrefabRef<GameObject>)(object)spawnObject)?.Prefab;
						EnemyBombThrower val4 = (((Object)(object)val3 != (Object)null) ? val3.GetComponentInChildren<EnemyBombThrower>(true) : null);
						if ((Object)(object)val4 != (Object)null && (Object)(object)val4.head != (Object)null)
						{
							val2 = ((Component)val4.head).gameObject;
							break;
						}
					}
				}
				if ((Object)(object)val2 == (Object)null)
				{
					Log.LogWarning((object)"[MeltdownCrew] head prefab not found; extra heads disabled.");
					return null;
				}
				GameObject val5 = Object.Instantiate<GameObject>(val2);
				((Object)val5).name = "MatsuMeltdownExtraHead";
				Object.DontDestroyOnLoad((Object)(object)val5);
				val5.SetActive(false);
				EnemyBombThrowerHead component = val5.GetComponent<EnemyBombThrowerHead>();
				if ((Object)(object)component != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)component);
				}
				val5.AddComponent<MeltdownExtraHead>();
				_meltdownHeadRef = NetworkPrefabs.RegisterNetworkPrefab("Matsu/MeltdownExtraHead", val5);
				if (_meltdownHeadRef == null)
				{
					Log.LogWarning((object)"[MeltdownCrew] RegisterNetworkPrefab returned null; extra heads disabled.");
				}
				else
				{
					Log.LogInfo((object)"[MeltdownCrew] Registered the extra-head network prefab.");
				}
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"[MeltdownCrew] head prefab build error: {arg}");
			}
			return _meltdownHeadRef;
		}

		public static void SpawnMeltdownHead(Vector3 pos, Quaternion rot, Vector3 forward, float factor)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				PrefabRef meltdownHeadPrefabRef = GetMeltdownHeadPrefabRef();
				if (meltdownHeadPrefabRef == null)
				{
					Log.LogWarning((object)"[MeltdownCrew] no head prefab ref; skipping spawn.");
					return;
				}
				GameObject val = NetworkPrefabs.SpawnNetworkPrefab(meltdownHeadPrefabRef, pos, rot, (byte)0, (object[])null);
				if ((Object)(object)val == (Object)null)
				{
					Log.LogWarning((object)"[MeltdownCrew] SpawnNetworkPrefab returned null.");
					return;
				}
				val.SetActive(true);
				MeltdownExtraHead component = val.GetComponent<MeltdownExtraHead>();
				if ((Object)(object)component == (Object)null)
				{
					Log.LogWarning((object)"[MeltdownCrew] spawned head has no driver component.");
					return;
				}
				component.Launch(factor, forward);
				Log.LogInfo((object)$"[MeltdownCrew] spawned extra head (factor {factor}, active={val.activeSelf}) at {pos}.");
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"[MeltdownCrew] spawn head error: {arg}");
			}
		}

		public void StartBalloonChain(List<GameObject> balloons, int damage, GameObject? popEffect)
		{
			if (balloons != null && balloons.Count != 0 && SemiFunc.IsMasterClientOrSingleplayer())
			{
				((MonoBehaviour)this).StartCoroutine(BalloonChainRoutine(balloons, damage, popEffect));
			}
		}

		private IEnumerator BalloonChainRoutine(List<GameObject> balloons, int damage, GameObject? popEffect)
		{
			foreach (GameObject balloon in balloons)
			{
				if ((Object)(object)balloon != (Object)null)
				{
					Vector3 position = balloon.transform.position;
					FusionShared.ExplodeAuthoritative(position, 0.7f, damage, 0);
					if ((Object)(object)popEffect != (Object)null)
					{
						Object.Instantiate<GameObject>(popEffect, position, Quaternion.identity);
					}
					Object.Destroy((Object)(object)balloon);
				}
				yield return (object)new WaitForSeconds(0.1f);
			}
		}
	}
	[HarmonyPatch(typeof(EnemyParent), "Spawn")]
	internal static class EnemyParent_Spawn_Patch
	{
		private static void Postfix(EnemyParent __instance)
		{
			MutationAttach.TryAttach(__instance);
		}
	}
	[HarmonyPatch(typeof(EnemyParent), "SpawnRPC")]
	internal static class EnemyParent_SpawnRPC_Patch
	{
		private static void Postfix(EnemyParent __instance)
		{
			MutationAttach.TryAttach(__instance);
		}
	}
	internal static class MutationAttach
	{
		private static float _boomdayPity;

		private static float _poltergeistPity;

		private static float _cleanupPity;

		private static float _snatcherPity;

		private static float _deathgazePity;

		private static int _boomdayPityLevel = -1;

		private static int _poltergeistPityLevel = -1;

		private static int _cleanupPityLevel = -1;

		private static int _snatcherPityLevel = -1;

		private static int _deathgazePityLevel = -1;

		private static bool _boomdayMutatedThisLevel;

		private static bool _poltergeistMutatedThisLevel;

		private static bool _cleanupMutatedThisLevel;

		private static bool _snatcherMutatedThisLevel;

		private static bool _deathgazeMutatedThisLevel;

		private static readonly Dictionary<int, bool> _boomdayMutatedIds = new Dictionary<int, bool>();

		private static readonly Dictionary<int, bool> _poltergeistMutatedIds = new Dictionary<int, bool>();

		private static readonly Dictionary<int, bool> _cleanupMutatedIds = new Dictionary<int, bool>();

		private static readonly Dictionary<int, bool> _snatcherMutatedIds = new Dictionary<int, bool>();

		private static readonly Dictionary<int, bool> _deathgazeMutatedIds = new Dictionary<int, bool>();

		public static void TryAttach(EnemyParent __instance)
		{
			try
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				bool flag = Time.time <= Plugin.ForceFuseUntil;
				int key = EnemyId(__instance);
				EnemyBirthdayBoy componentInChildren = ((Component)__instance).GetComponentInChildren<EnemyBirthdayBoy>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					float chance = (flag ? 1f : GetMutationChance(ref _boomdayPity, ref _boomdayPityLevel, ref _boomdayMutatedThisLevel, _boomdayMutatedIds));
					bool value;
					bool flag2 = _boomdayMutatedIds.TryGetValue(key, out value) && value;
					if ((Object)(object)((Component)componentInChildren).GetComponent<BoomdayBoyFusion>() == (Object)null && (flag2 || ShouldMutate(__instance, chance)))
					{
						((Component)componentInChildren).gameObject.AddComponent<BoomdayBoyFusion>();
						_boomdayMutatedThisLevel = true;
						_boomdayPity = 0f;
						_boomdayMutatedIds[key] = true;
						Plugin.Log.LogInfo((object)"[BoomdayBoy] A Birthday Boy became a Boomday Boy.");
					}
					return;
				}
				EnemyFloater componentInChildren2 = ((Component)__instance).GetComponentInChildren<EnemyFloater>();
				if ((Object)(object)componentInChildren2 != (Object)null)
				{
					float chance2 = (flag ? 1f : GetMutationChance(ref _poltergeistPity, ref _poltergeistPityLevel, ref _poltergeistMutatedThisLevel, _poltergeistMutatedIds));
					bool value2;
					bool flag3 = _poltergeistMutatedIds.TryGetValue(key, out value2) && value2;
					if ((Object)(object)((Component)componentInChildren2).GetComponent<PoltergeistFusion>() == (Object)null && (flag3 || ShouldMutate(__instance, chance2)))
					{
						((Component)componentInChildren2).gameObject.AddComponent<PoltergeistFusion>();
						_poltergeistMutatedThisLevel = true;
						_poltergeistPity = 0f;
						_poltergeistMutatedIds[key] = true;
						Plugin.Log.LogInfo((object)"[Poltergeist] A Mentalist mutated into a Poltergeist.");
					}
					return;
				}
				EnemyBombThrower componentInChildren3 = ((Component)__instance).GetComponentInChildren<EnemyBombThrower>();
				if ((Object)(object)componentInChildren3 != (Object)null)
				{
					float chance3 = (flag ? 1f : GetMutationChance(ref _cleanupPity, ref _cleanupPityLevel, ref _cleanupMutatedThisLevel, _cleanupMutatedIds));
					bool value3;
					bool flag4 = _cleanupMutatedIds.TryGetValue(key, out value3) && value3;
					if ((Object)(object)((Component)componentInChildren3).GetComponent<CleanupCrewFusion>() == (Object)null && (flag4 || ShouldMutate(__instance, chance3)))
					{
						((Component)componentInChildren3).gameObject.AddComponent<CleanupCrewFusion>();
						_cleanupMutatedThisLevel = true;
						_cleanupPity = 0f;
						_cleanupMutatedIds[key] = true;
						Plugin.Log.LogInfo((object)"[MeltdownCrew] A Cleanup Crew mutated into a Meltdown Crew.");
					}
					return;
				}
				EnemyHidden componentInChildren4 = ((Component)__instance).GetComponentInChildren<EnemyHidden>();
				if ((Object)(object)componentInChildren4 != (Object)null)
				{
					float chance4 = (flag ? 1f : GetMutationChance(ref _snatcherPity, ref _snatcherPityLevel, ref _snatcherMutatedThisLevel, _snatcherMutatedIds));
					bool value4;
					bool flag5 = _snatcherMutatedIds.TryGetValue(key, out value4) && value4;
					if ((Object)(object)((Component)componentInChildren4).GetComponent<SnatcherFusion>() == (Object)null && (flag5 || ShouldMutate(__instance, chance4)))
					{
						((Component)componentInChildren4).gameObject.AddComponent<SnatcherFusion>();
						_snatcherMutatedThisLevel = true;
						_snatcherPity = 0f;
						_snatcherMutatedIds[key] = true;
						Plugin.Log.LogInfo((object)"[Snatcher] A Hidden mutated into a Snatcher.");
					}
					return;
				}
				EnemyCeilingEye componentInChildren5 = ((Component)__instance).GetComponentInChildren<EnemyCeilingEye>();
				if ((Object)(object)componentInChildren5 != (Object)null)
				{
					float chance5 = (flag ? 1f : GetMutationChance(ref _deathgazePity, ref _deathgazePityLevel, ref _deathgazeMutatedThisLevel, _deathgazeMutatedIds));
					bool value5;
					bool flag6 = _deathgazeMutatedIds.TryGetValue(key, out value5) && value5;
					if ((Object)(object)((Component)componentInChildren5).GetComponent<PeeperFusion>() == (Object)null && (flag6 || ShouldMutate(__instance, chance5)))
					{
						((Component)componentInChildren5).gameObject.AddComponent<PeeperFusion>();
						_deathgazeMutatedThisLevel = true;
						_deathgazePity = 0f;
						_deathgazeMutatedIds[key] = true;
						Plugin.Log.LogInfo((object)"[Deathgaze] A Peeper mutated into a Deathgaze.");
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Mutation] attach error: {arg}");
			}
		}

		private static float GetMutationChance(ref float pity, ref int lastLevel, ref bool mutatedThisLevel, Dictionary<int, bool> mutatedIds)
		{
			RunManager instance = RunManager.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return 0f;
			}
			int num = instance.levelsCompleted + 1;
			if (lastLevel == -1)
			{
				lastLevel = num;
			}
			else if (num != lastLevel)
			{
				if (mutatedThisLevel)
				{
					pity = 0f;
				}
				else
				{
					pity += (float)lastLevel * Plugin.MutationChancePerLevel.Value;
				}
				mutatedThisLevel = false;
				lastLevel = num;
				mutatedIds.Clear();
			}
			return Mathf.Clamp((float)num * Plugin.MutationChancePerLevel.Value + pity, 0f, Plugin.MutationMaxChance.Value);
		}

		private static int EnemyId(EnemyParent instance)
		{
			PhotonView photonView = ((MonoBehaviourPun)instance).photonView;
			if (!((Object)(object)photonView != (Object)null))
			{
				return ((Object)instance).GetInstanceID();
			}
			return photonView.ViewID;
		}

		private static bool ShouldMutate(EnemyParent instance, float chance)
		{
			if (chance <= 0f)
			{
				return false;
			}
			if (chance >= 1f)
			{
				return true;
			}
			PhotonView photonView = ((MonoBehaviourPun)instance).photonView;
			if ((Object)(object)photonView == (Object)null)
			{
				return Random.value <= chance;
			}
			int num = photonView.ViewID * -1640531535;
			int num2 = (num ^ (num >>> 13)) * -1640531535;
			return (float)(uint)((num2 ^ (num2 >>> 16)) & 0xFFFFFF) / 16777216f < chance;
		}
	}
	[HarmonyPatch(typeof(EnemyBirthdayBoy), "OnDeath")]
	internal static class EnemyBirthdayBoy_OnDeath_Patch
	{
		private static void Postfix(EnemyBirthdayBoy __instance)
		{
			try
			{
				if (SemiFunc.IsMasterClientOrSingleplayer() && !((Object)(object)__instance == (Object)null))
				{
					BoomdayBoyFusion component = ((Component)__instance).GetComponent<BoomdayBoyFusion>();
					if ((Object)(object)component != (Object)null)
					{
						component.Detonate();
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[BoomdayBoy] OnDeath patch error: {arg}");
			}
		}
	}
}