Decompiled source of Guest Role v2.13.67

BepInEx/plugins/Guest-Role/Guest-Role.dll

Decompiled an hour ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using REPOLib.Modules;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("2.13.66.0")]
[assembly: TargetFramework(".NETStandard,Version=v2.1")]
[assembly: AssemblyVersion("2.13.66.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace GuestMedic
{
	internal static class AgentEnemyName
	{
		internal static string Resolve(EnemyParent enemy)
		{
			if (!Object.op_Implicit((Object)(object)enemy))
			{
				return null;
			}
			try
			{
				LocalizedAsset enemyNameLocalized = enemy.enemyNameLocalized;
				if (Object.op_Implicit((Object)(object)enemyNameLocalized) && enemyNameLocalized.IsValid() && enemyNameLocalized.ExistsForLocale((Locale)null))
				{
					string localizedString = enemyNameLocalized.GetLocalizedString((Locale)null);
					if (!string.IsNullOrWhiteSpace(localizedString))
					{
						return localizedString.Trim();
					}
				}
			}
			catch (Exception)
			{
			}
			if (!string.IsNullOrWhiteSpace(enemy.enemyName))
			{
				return enemy.enemyName.Trim();
			}
			return null;
		}
	}
	[BepInPlugin("Guest-Role", "Guest-Role", "2.13.66")]
	[BepInIncompatibility("local.bei.guesthealthpackgrant")]
	[BepInDependency("REPOLib", "4.2.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		private sealed class AgentEnergyScope
		{
			internal Plugin Owner;

			internal ItemBattery Battery;

			internal ItemGun Gun;

			internal PlayerAvatar Player;

			internal float OriginalDrain;

			internal bool Reduced;
		}

		private static class AgentEnergyHooks
		{
			internal static void Prefix(Component __instance, out AgentEnergyScope __state)
			{
				__state = null;
				Plugin current = Current;
				if (Object.op_Implicit((Object)(object)current) && Object.op_Implicit((Object)(object)GameManager.instance) && SemiFunc.IsMasterClientOrSingleplayer())
				{
					PhysGrabObject component = __instance.GetComponent<PhysGrabObject>();
					PlayerAvatar player = (PlayerAvatar)(Object.op_Implicit((Object)(object)component) ? /*isinst with value type is only supported in some contexts*/: null);
					ItemGun val = (ItemGun)(object)((__instance is ItemGun) ? __instance : null);
					AgentEnergyScope agentEnergyScope = new AgentEnergyScope
					{
						Owner = current,
						Battery = __instance.GetComponent<ItemBattery>(),
						Gun = val,
						Player = player,
						OriginalDrain = (Object.op_Implicit((Object)(object)val) ? val.batteryDrain : 0f),
						Reduced = (current.IsAssassin(player) && !Object.op_Implicit((Object)(object)__instance.GetComponent<ItemGunRevolver>()))
					};
					current.agentEnergyScopes.Push(agentEnergyScope);
					__state = agentEnergyScope;
					if (agentEnergyScope.Reduced && Object.op_Implicit((Object)(object)val))
					{
						val.batteryDrain = AgentEnergyRules.SpendAmount(agentEnergyScope.OriginalDrain);
					}
				}
			}

			internal static Exception Finalizer(AgentEnergyScope __state, Exception __exception)
			{
				if (__state == null)
				{
					return __exception;
				}
				if (__state.Reduced && Object.op_Implicit((Object)(object)__state.Gun))
				{
					__state.Gun.batteryDrain = __state.OriginalDrain;
				}
				if (__state.Owner.agentEnergyScopes.Count > 0 && __state.Owner.agentEnergyScopes.Peek() == __state)
				{
					__state.Owner.agentEnergyScopes.Pop();
				}
				return __exception;
			}
		}

		private sealed class AgentPendingDraw
		{
			internal PlayerAvatar Owner;

			internal object Room;
		}

		private sealed class AssassinDamageScope
		{
			internal PlayerAvatar Player;

			internal Enemy Target;

			internal bool? Unaware;

			internal bool Firearm;
		}

		private static class AssassinHitHooks
		{
			internal static void Prefix(HurtCollider __instance, Enemy __0, out bool __state)
			{
				AssassinAttackPrefix(__instance, __0, out __state);
			}

			internal static Exception Finalizer(bool __state, Exception __exception)
			{
				return AssassinAttackFinalizer(__state, __exception);
			}
		}

		private static class AssassinCollisionHooks
		{
			internal static void Prefix(PhysGrabObjectImpactDetector __instance, out bool __state)
			{
				AssassinCollisionPrefix(__instance, out __state);
			}

			internal static Exception Finalizer(bool __state, Exception __exception)
			{
				return AssassinAttackFinalizer(__state, __exception);
			}
		}

		private static class AssassinMovementHooks
		{
			internal static void Prefix(PlayerAvatar __instance, out float? __state)
			{
				AssassinMovementPrefix(__instance, out __state);
			}

			internal static Exception Finalizer(PlayerAvatar __instance, float? __state, Exception __exception)
			{
				return AssassinMovementFinalizer(__instance, __state, __exception);
			}
		}

		private static class AssassinVoiceHooks
		{
			internal static void Prefix(PlayerVoiceChat __instance, out float? __state)
			{
				AssassinVoicePrefix(__instance, out __state);
			}

			internal static Exception Finalizer(PlayerVoiceChat __instance, float? __state, Exception __exception)
			{
				return AssassinVoiceFinalizer(__instance, __state, __exception);
			}
		}

		private sealed class BirdSaveState
		{
			internal SortedDictionary<string, Dictionary<string, int>> Original;

			internal SortedDictionary<string, Dictionary<string, int>> Copy;
		}

		private sealed class BladeItem
		{
			internal string SavedName;

			internal GameObject Object;

			internal PhysGrabObject Phys;

			internal ItemMelee Melee;

			internal ItemBattery Battery;

			internal HurtCollider Hit;

			internal BoxCollider Box;

			internal SphereCollider Sphere;

			internal Collider[] Colliders;

			internal Collider[] BodyColliders;

			internal Collider[] IgnoredColliders;

			internal bool PhysicalFollowing;

			internal double StowingAt = double.NaN;

			internal double StowPositionSentAt;

			internal Vector3 StowOrigin;

			internal bool RemoteWind;

			internal float ReadyAt;

			internal int ReadyFrame;

			internal BladerAppearance Appearance;

			internal double WarmUntil;

			internal float EnemyEnergyCost;

			internal bool Ready;

			internal bool Presented;

			internal bool BrokenVisual;

			internal int OriginalEnemyDamage;

			internal Transform OriginalForceGrabPoint;

			internal PhysGrabObjectImpactDetector Impact;

			internal bool OriginalImpactHurt;
		}

		private struct BladePose
		{
			internal Vector3 Position;

			internal Vector3 Center;

			internal Vector3 HalfSize;

			internal Quaternion Rotation;

			internal Quaternion HitRotation;

			internal long Swing;

			internal bool Wind;
		}

		private sealed class BladerStrike
		{
			internal Plugin Owner;

			internal int Original;

			internal BladerSwordStunOverride Stun;
		}

		private static class BladerCombatHooks
		{
			internal static void Prefix(HurtCollider __instance, Enemy __0, out BladerStrike __state)
			{
				//IL_0135: Unknown result type (might be due to invalid IL or missing references)
				__state = null;
				Plugin current = Current;
				if (!Object.op_Implicit((Object)(object)current) || !current.BladerActive || !Object.op_Implicit((Object)(object)__0) || __instance.enemyKill || __instance.deathPit || !__instance.enemyLogic || __instance.enemyDamage <= 0 || current.bladerBoosting.Contains(__instance))
				{
					return;
				}
				PlayerAvatar player = current.AssassinAttackOwner(__instance);
				PhysGrabObject val = current.BladerHeldSword(player);
				if (!Object.op_Implicit((Object)(object)val) || ((Object)(object)__instance != (Object)(object)current.bladerDamageSource && (Object)(object)((Component)__instance).GetComponentInParent<PhysGrabObject>() != (Object)(object)val))
				{
					return;
				}
				object? value = comboEnemyHealth.GetValue(__0);
				EnemyHealth val2 = (EnemyHealth)((value is EnemyHealth) ? value : null);
				if (Object.op_Implicit((Object)(object)val2) && (int)comboHealth.GetValue(val2) > 0)
				{
					__state = new BladerStrike
					{
						Owner = current,
						Original = __instance.enemyDamage
					};
					current.bladerBoosting.Add(__instance);
					bool flag = current.IsBladerSword(((Component)val).gameObject) || (Object)(object)__instance == (Object)(object)current.bladerDamageSource;
					if (flag)
					{
						__instance.enemyDamage = BladerDepletedRules.Damage(current.bladerPrimary.Battery.batteryLife, __instance.enemyDamage);
					}
					else
					{
						__instance.enemyDamage = BladerCombatRules.Damage(__instance.enemyDamage);
					}
					__state.Stun = new BladerSwordStunOverride(__instance, __0.Type, flag);
				}
			}

			internal static Exception Finalizer(HurtCollider __instance, BladerStrike __state, Exception __exception)
			{
				if (__state != null)
				{
					if (Object.op_Implicit((Object)(object)__instance))
					{
						__instance.enemyDamage = __state.Original;
						__state.Stun?.Restore(__instance);
					}
					__state.Owner.bladerBoosting.Remove(__instance);
				}
				return __exception;
			}
		}

		private sealed class BladerKnockbackState
		{
			internal Plugin Owner;

			internal BladerForceScope.Frame Frame;
		}

		private static class BladerKnockbackHooks
		{
			internal static void Prefix(HurtCollider __instance, PlayerAvatar __0, out BladerKnockbackState __state)
			{
				__state = null;
				Plugin current = Current;
				if (Object.op_Implicit((Object)(object)current) && current.BladerActive && Object.op_Implicit((Object)(object)__0))
				{
					bool reduce = NativeContext.IsLocal(__0) && current.BladerProtected(__0, __instance.enemyHost);
					__state = new BladerKnockbackState
					{
						Owner = current,
						Frame = current.bladerForceScope.Enter(__0, reduce)
					};
				}
			}

			internal static Exception Finalizer(BladerKnockbackState __state, Exception __exception)
			{
				__state?.Owner.bladerForceScope.Exit(__state.Frame);
				return __exception;
			}
		}

		private sealed class BomberDeath
		{
			internal readonly BomberLife Life = new BomberLife();

			internal PlayerAvatar Player;

			internal HurtCollider Hit;

			internal Vector3 Position;

			internal float VisualDeadline;

			internal double StartedAt;

			internal bool VisualPending;
		}

		private static class BomberRunHooks
		{
			internal static void Prefix(RunManager __instance, out bool __state)
			{
				__state = false;
				if (Object.op_Implicit((Object)(object)Current) && (Current.BomberAwaitingRevival() || Current.EaterAwaitingRevival()) && !(bool)bomberWipeDisabled.GetValue(__instance))
				{
					bomberWipeDisabled.SetValue(__instance, true);
					__state = true;
				}
			}

			internal static Exception Finalizer(RunManager __instance, bool __state, Exception __exception)
			{
				if (__state && Object.op_Implicit((Object)(object)__instance))
				{
					bomberWipeDisabled.SetValue(__instance, false);
				}
				return __exception;
			}
		}

		private static class BomberDeathHooks
		{
			internal struct Snapshot
			{
				internal bool Dead;

				internal Vector3 Position;
			}

			internal static void Prefix(PlayerAvatar __instance, bool ___deadSet, out Snapshot __state)
			{
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				__state = new Snapshot
				{
					Dead = ___deadSet,
					Position = ((Component)__instance).transform.position
				};
			}

			internal static void Postfix(PlayerAvatar __instance, bool ___deadSet, Snapshot __state)
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				if (!__state.Dead && ___deadSet && Object.op_Implicit((Object)(object)Current))
				{
					Current.TriggerBomberDeath(__instance, __state.Position);
				}
			}
		}

		private static class BomberHitHooks
		{
			internal sealed class Snapshot
			{
				internal BomberDeath Death;

				internal EnemyHealth Health;
			}

			internal static void Prefix(HurtCollider __instance, Enemy __0, out Snapshot __state)
			{
				__state = null;
				Plugin current = Current;
				if (!Object.op_Implicit((Object)(object)current) || !current.BomberActive)
				{
					return;
				}
				BomberDeath bomberDeath = current.bomberDeath;
				if (bomberDeath != null && !((Object)(object)bomberDeath.Hit != (Object)(object)__instance) && Object.op_Implicit((Object)(object)__0))
				{
					object? value = bomberEnemyHealth.GetValue(__0);
					EnemyHealth val = (EnemyHealth)((value is EnemyHealth) ? value : null);
					if (Object.op_Implicit((Object)(object)val) && (int)bomberHealth.GetValue(val) > 0 && !(bool)bomberDead.GetValue(val) && !(bool)bomberDying.GetValue(val))
					{
						__state = new Snapshot
						{
							Death = bomberDeath,
							Health = val
						};
					}
				}
			}

			internal static void Postfix(Snapshot __state)
			{
				if (__state == null || !Object.op_Implicit((Object)(object)__state.Health))
				{
					return;
				}
				Plugin current = Current;
				if (Object.op_Implicit((Object)(object)current) && current.BomberActive && current.bomberDeath == __state.Death)
				{
					bool deadAfter = (int)bomberHealth.GetValue(__state.Health) <= 0 && ((bool)bomberDead.GetValue(__state.Health) || (bool)bomberDying.GetValue(__state.Health));
					if (__state.Death.Life.RecordKill(aliveBefore: true, deadAfter, Time.timeAsDouble))
					{
						((BaseUnityPlugin)current).Logger.LogInfo((object)"Bomber explosion killed an enemy; revival scheduled in 3 seconds.");
					}
				}
			}
		}

		private sealed class BomberSupplyItem
		{
			internal GameObject Object;

			internal string Name;

			internal string Recipient;

			internal float ReadyAt;

			internal float RetryAt;

			internal int ReadyFrame;

			internal bool Delivered;
		}

		private sealed class EaterRecovery
		{
			internal PlayerAvatar Player;

			internal ExtractionPoint Point;

			internal int Health;

			internal Vector3 Position;

			internal double Deadline;

			internal double LastDanger = double.NegativeInfinity;

			internal bool Died;

			internal bool Raised;

			internal bool ReviveSent;
		}

		private static class EaterHooks
		{
			internal static bool AllowBox(ItemValuableBox __instance)
			{
				if (Object.op_Implicit((Object)(object)Current))
				{
					return (Object)(object)__instance != (Object)(object)Current.eaterBox;
				}
				return true;
			}

			internal static bool AllowGrab(PhysGrabObject __instance)
			{
				if (Object.op_Implicit((Object)(object)Current))
				{
					return (Object)(object)__instance != (Object)(object)Current.eaterPhys;
				}
				return true;
			}

			internal static bool AllowEquip(ItemEquippable __instance)
			{
				if (Object.op_Implicit((Object)(object)Current))
				{
					return (Object)(object)((Component)__instance).gameObject != (Object)(object)Current.eaterCarrier;
				}
				return true;
			}

			internal static void Value(ItemValuableBox __instance, ref float newValue)
			{
				Plugin current = Current;
				if (Object.op_Implicit((Object)(object)current) && (Object)(object)__instance == (Object)(object)current.eaterBox && !current.eaterValueWrite && !current.eaterExtracting)
				{
					newValue = current.eaterRules.Balance(current.eaterSelected);
				}
			}

			internal static void Haul()
			{
				Plugin p = Current;
				if (Object.op_Implicit((Object)(object)p) && p.EaterActive)
				{
					p.EaterSafely(delegate
					{
						p.SyncEaterHaul(p.EaterPlayer());
					});
				}
			}

			internal static void Point(ExtractionPoint __instance)
			{
				Plugin p = Current;
				if (Object.op_Implicit((Object)(object)p))
				{
					p.EaterSafely(delegate
					{
						p.ObserveEaterPoint(__instance);
					});
				}
			}

			internal static void PointAfter(ExtractionPoint __instance)
			{
				Plugin current = Current;
				if (Object.op_Implicit((Object)(object)current) && current.EaterActive)
				{
					current.EaterSafely(current.TickEaterRecovery);
				}
			}

			internal static void Extract(ItemValuableBox __instance)
			{
				Plugin current = Current;
				if (Object.op_Implicit((Object)(object)current) && current.EaterActive && !((Object)(object)current.eaterBox != (Object)(object)__instance))
				{
					current.eaterLockedValue = current.eaterRules.Balance(current.eaterSelected);
					current.eaterExtracting = true;
				}
			}

			internal static void Settled(ItemValuableBox __instance)
			{
				Plugin current = Current;
				if (Object.op_Implicit((Object)(object)current) && current.EaterActive && !((Object)(object)current.eaterBox != (Object)(object)__instance) && current.eaterExtracting)
				{
					current.eaterRules.Settle(current.eaterSelected, current.eaterLockedValue);
					current.eaterLockedValue = 0;
					current.eaterExtracting = false;
					current.eaterLinked = false;
				}
			}

			internal static void Cancel(ExtractionPoint __instance, bool __result)
			{
				Plugin p = Current;
				if (__result && Object.op_Implicit((Object)(object)p) && p.EaterActive && !((Object)(object)p.eaterRecovery?.Point != (Object)(object)__instance))
				{
					p.EaterSafely(delegate
					{
						p.eaterExtracting = false;
						p.eaterLockedValue = 0;
						p.SetEaterValue(p.eaterRules.Balance(p.eaterSelected));
					});
				}
			}

			internal static bool AvatarRevive(PlayerAvatar __instance)
			{
				Plugin current = Current;
				EaterRecovery eaterRecovery = (Object.op_Implicit((Object)(object)current) ? current.eaterRecovery : null);
				if (eaterRecovery != null && eaterRecovery.Died && !((Object)(object)eaterRecovery.Player != (Object)(object)__instance))
				{
					return eaterRecovery.Raised;
				}
				return true;
			}

			internal static bool HeadRevive(PlayerDeathHead __instance)
			{
				Plugin current = Current;
				EaterRecovery eaterRecovery = (Object.op_Implicit((Object)(object)current) ? current.eaterRecovery : null);
				if (eaterRecovery != null && eaterRecovery.Died && !((Object)(object)eaterRecovery.Player != (Object)(object)__instance.playerAvatar))
				{
					return eaterRecovery.Raised;
				}
				return true;
			}

			internal static void HurtBefore(PlayerHealth __instance)
			{
				HealthBefore(__instance, 0);
			}

			internal static void HealthBefore(PlayerHealth __instance, int healthNew)
			{
				Plugin current = Current;
				EaterRecovery eaterRecovery = (Object.op_Implicit((Object)(object)current) ? current.eaterRecovery : null);
				if (eaterRecovery != null && Object.op_Implicit((Object)(object)eaterRecovery.Player) && !((Object)(object)eaterRecovery.Player.playerHealth != (Object)(object)__instance) && !eaterRecovery.Died)
				{
					int num = current.native.Health(eaterRecovery.Player);
					if (num > 0)
					{
						eaterRecovery.Health = num;
					}
				}
			}

			internal static void DeathBefore(PlayerAvatar __instance, out bool __state)
			{
				__state = Object.op_Implicit((Object)(object)Current) && Current.native.IsDead(__instance);
			}

			internal static void Death(PlayerAvatar __instance, int enemyIndex, bool __state)
			{
				Plugin p = Current;
				EaterRecovery eaterRecovery = (Object.op_Implicit((Object)(object)p) ? p.eaterRecovery : null);
				if (!Object.op_Implicit((Object)(object)p))
				{
					return;
				}
				p.EaterSafely(delegate
				{
					p.ApplyEaterDeathLoss(__instance, __state);
				});
				if (!__state && eaterRecovery != null && !((Object)(object)eaterRecovery.Player != (Object)(object)__instance) && p.native.IsDead(__instance))
				{
					if (EaterRules.CrushCandidate(enemyIndex, EaterInside(eaterRecovery.Point, __instance), EaterDanger(eaterRecovery.Point), Time.timeAsDouble - eaterRecovery.LastDanger))
					{
						eaterRecovery.Died = true;
					}
					else
					{
						p.eaterRecovery = null;
					}
				}
			}
		}

		private sealed class MeleeSpecialistHitState
		{
			internal Plugin Owner;

			internal int Original;

			internal BrawlerTumbleStunOverride Stun;

			internal BrawlerAttack Attack;

			internal EnemyHealth Health;

			internal int BeforeHealth;

			internal int Step;

			internal double HitTime;
		}

		private sealed class MuscleReleaseNotice
		{
			internal PhysGrabObject Object;

			internal double Until;
		}

		private sealed class MuscleTickLink
		{
			internal PhysGrabObject Object;

			internal int Revision;
		}

		private sealed class DrawbackExplosionContext
		{
			internal PlayerAvatar Owner;
		}

		private sealed class DrawbackDamageState
		{
			internal Plugin Plugin;

			internal RoleDrawbackDamageScopes<PlayerAvatar, Enemy>.Frame Frame;
		}

		private static class DrawbackHitHooks
		{
			internal static void Prefix(HurtCollider __instance, Enemy __0, out DrawbackDamageState __state)
			{
				__state = null;
				Plugin current = Current;
				if (!Object.op_Implicit((Object)(object)current) || !current.DrawbackDamageAuthority)
				{
					return;
				}
				try
				{
					PlayerAvatar actor = ((__instance.deathPit || __instance.enemyKill) ? null : current.DrawbackHitOwner(__instance));
					__state = new DrawbackDamageState
					{
						Plugin = current,
						Frame = current.drawbackDamageScopes.Push(actor, __0, DrawbackHitKind(__instance))
					};
				}
				catch (Exception e)
				{
					current.StopRoleDrawbackDamage(e);
				}
			}

			internal static Exception Finalizer(DrawbackDamageState __state, Exception __exception)
			{
				__state?.Plugin.drawbackDamageScopes.End(__state.Frame);
				return __exception;
			}
		}

		private static class DrawbackCollisionHooks
		{
			internal static void Prefix(PhysGrabObjectImpactDetector __instance, Collision __0, out DrawbackDamageState __state)
			{
				__state = null;
				Plugin current = Current;
				if (!Object.op_Implicit((Object)(object)current) || !current.DrawbackDamageAuthority)
				{
					return;
				}
				try
				{
					__state = new DrawbackDamageState
					{
						Plugin = current,
						Frame = current.drawbackDamageScopes.Push(null, null, DrawbackAttackKind.Direct)
					};
				}
				catch (Exception e)
				{
					current.StopRoleDrawbackDamage(e);
				}
			}

			internal static Exception Finalizer(DrawbackDamageState __state, Exception __exception)
			{
				__state?.Plugin.drawbackDamageScopes.End(__state.Frame);
				return __exception;
			}
		}

		private static class DrawbackHammerHooks
		{
			internal static void Prefix(ItemMeleeInflatableHammer __instance, out DrawbackExplosionContext __state)
			{
				__state = null;
				Plugin current = Current;
				if (!Object.op_Implicit((Object)(object)current) || !current.DrawbackDamageAuthority)
				{
					return;
				}
				try
				{
					__state = new DrawbackExplosionContext
					{
						Owner = current.MeleeSpecialistMeleeUser((Component)(object)__instance)
					};
					current.drawbackExplosionSources.Push(__state);
				}
				catch (Exception e)
				{
					current.StopRoleDrawbackDamage(e);
				}
			}

			internal static Exception Finalizer(DrawbackExplosionContext __state, Exception __exception)
			{
				Plugin current = Current;
				if (__state != null && Object.op_Implicit((Object)(object)current) && current.drawbackExplosionSources.Count > 0)
				{
					if (current.drawbackExplosionSources.Peek() == __state)
					{
						current.drawbackExplosionSources.Pop();
					}
					else
					{
						current.drawbackExplosionSources.Clear();
					}
				}
				return __exception;
			}
		}

		private sealed class ExplanationRequest
		{
			internal RoleExplanationWindow.Assignment Assignment;

			internal PlayerAvatar Player;

			internal string Text;

			internal string Locale;

			internal float NotBefore;

			internal float Deadline;
		}

		private sealed class RoleAnnouncement
		{
			internal PlayerAvatar Player;

			internal string Id;

			internal string Text;

			internal int Role;

			internal object Room;

			internal float Deadline;
		}

		private sealed class TankRevival
		{
			internal int Health;

			internal float Deadline;

			internal bool Requested;
		}

		private sealed class TankDamageContext
		{
			internal PlayerAvatar Victim;

			internal int Before;

			internal int Incoming;

			internal bool Handled;

			internal bool Local;

			internal bool Enemy;

			internal bool Ignore;

			internal bool InitialHealth;

			internal bool Uninitialized;

			internal bool VulnerabilityApplied;

			internal int NativeMaximum;

			internal int RestoredMaximum;

			internal int Upgrades;
		}

		private sealed class TankModeRevival
		{
			internal int Health;

			internal double StartedAt;

			internal double Deadline;

			internal bool Requested;

			internal bool Pit;
		}

		private sealed class PendingTrap
		{
			internal GameObject Object;

			internal PlayerAvatar Owner;

			internal Vector3 Ground;

			internal Quaternion Rotation;

			internal int Frame;

			internal ItemEquippable Source;

			internal string SourceName;

			internal Dictionary<string, int> ChargeStore;

			internal string Name;

			internal double Deadline;

			internal double IdentityRetryAt;

			internal bool ArmRequested;

			internal bool Positioned;

			internal readonly TrapperPlacementRules Placement = new TrapperPlacementRules();
		}

		private sealed class TrapperChargeLoadState
		{
			internal Dictionary<string, int> Charges;

			internal Dictionary<string, int> Before;
		}

		private sealed class TrapperChargeIdentityChange
		{
			internal StatsManager Stats;

			internal Dictionary<string, int> Items;

			internal string Name;

			internal int ItemIndex;
		}

		private sealed class TrapperSourceDepletion
		{
			internal GameObject Object;

			internal ItemEquippable Source;

			internal PhotonView View;

			internal StatsManager Stats;

			internal Dictionary<string, int> ChargeStore;

			internal object Room;

			internal object Stage;

			internal string Name;

			internal string PlayerId;

			internal string LastError;

			internal int ItemIndex;

			internal int Slot;

			internal int ViewId;

			internal bool RemovalAttempted;

			internal bool StatsRemoved;

			internal bool Destroyed;

			internal bool Synced;

			internal double RetryAt;
		}

		private static class TrapperSearchHooks
		{
			internal static void Prefix(Component __instance, out Plugin __state)
			{
				__state = null;
				Plugin current = Current;
				if (!Object.op_Implicit((Object)(object)current) || !current.hostReady || current.trapperSelected == null || !current.modEnabled.Value)
				{
					return;
				}
				if (__instance is ChompBookTrap)
				{
					object? value = trapperBookTarget.GetValue(__instance);
					Transform val = (Transform)((value is Transform) ? value : null);
					if (Object.op_Implicit((Object)(object)val) && current.TrapperDetectionIgnored(TrapperColliderPlayer((Component)(object)val)))
					{
						trapperBookTarget.SetValue(__instance, null);
					}
				}
				current.trapperSearchDepth++;
				__state = current;
			}

			internal static Exception Finalizer(Plugin __state, Exception __exception)
			{
				if ((Object)(object)__state != (Object)null && __state.trapperSearchDepth > 0)
				{
					__state.trapperSearchDepth--;
				}
				return __exception;
			}
		}

		private sealed class TrapperMineCarry
		{
			internal readonly TrapperCarryVelocityGuard Guard = new TrapperCarryVelocityGuard();

			internal PlayerAvatar Carrier;

			internal object Room;

			internal object Stage;
		}

		private sealed class UpgradeRestrictionEntry
		{
			internal ItemToggle Toggle;

			internal PhotonView View;

			internal int ViewId;

			internal int Actor;

			internal bool Local;

			internal bool Desired;

			internal Player Recipient;

			internal PlayerAvatar Avatar;

			internal object Room;

			internal UpgradeRestrictionLeaseRules Rules;
		}

		private readonly Stack<AgentEnergyScope> agentEnergyScopes = new Stack<AgentEnergyScope>();

		private readonly ConditionalWeakTable<ItemBattery, AgentEnergyRules> agentEnergyDebts = new ConditionalWeakTable<ItemBattery, AgentEnergyRules>();

		private static readonly FieldInfo agentEnergyBars = AccessTools.Field(typeof(ItemBattery), "batteryLifeInt");

		private static readonly FieldInfo agentInventoryHeld = AccessTools.Field(typeof(PhysGrabber), "grabbedPhysGrabObject");

		private static readonly FieldInfo agentInventoryInstanceName = AccessTools.Field(typeof(ItemAttributes), "instanceName");

		private static readonly FieldInfo agentInventoryState = AccessTools.Field(typeof(ItemEquippable), "currentState");

		private static readonly FieldInfo agentInventoryUnequipping = AccessTools.Field(typeof(ItemEquippable), "isUnequipping");

		private static readonly FieldInfo agentInventoryForcedUnequip = AccessTools.Field(typeof(ItemEquippable), "isForceUnequipping");

		private static readonly MethodInfo agentInventoryStateRpc = AccessTools.Method(typeof(ItemEquippable), "RPC_UpdateItemState", (Type[])null, (Type[])null);

		private readonly Dictionary<ItemEquippable, AgentPendingDraw> agentPendingDraws = new Dictionary<ItemEquippable, AgentPendingDraw>();

		private readonly List<ItemEquippable> agentFinishedDraws = new List<ItemEquippable>();

		private readonly AgentRadarRules agentRadar = new AgentRadarRules();

		private bool agentRadarFailed;

		private static readonly FieldInfo agentMapActive = AccessTools.Field(typeof(MapToolController), "Active");

		private static readonly FieldInfo agentSpeaking = AccessTools.Field(typeof(TTSVoice), "isSpeaking");

		private static readonly FieldInfo agentEnemySpawned = AccessTools.Field(typeof(EnemyParent), "Spawned");

		private static readonly FieldInfo agentEnemyDead = AccessTools.Field(typeof(EnemyHealth), "dead");

		private static readonly FieldInfo agentEnemyDying = AccessTools.Field(typeof(EnemyHealth), "deadImpulse");

		private static readonly FieldInfo agentEnemyHealth = AccessTools.Field(typeof(EnemyHealth), "healthCurrent");

		private static readonly string[] agentSuspendedUpgradeNames = new string[4] { "Strength", "Range", "Throw", "Speed" };

		private static readonly FieldInfo agentUpgradeRestarting = AccessTools.Field(typeof(RunManager), "restarting");

		private Harmony agentUpgradePatches;

		private bool agentUpgradesReady;

		private bool agentUpgradeWriting;

		private object agentUpgradeRoom;

		private object agentUpgradeStage;

		private StatsManager agentUpgradeStats;

		private PlayerAvatar agentUpgradeAvatar;

		private PlayerAvatar agentUpgradeReadyAvatar;

		private string agentUpgradePlayer;

		private double agentUpgradeReadyAt;

		private readonly List<AgentUpgradeLedger> agentUpgradeLedgers = new List<AgentUpgradeLedger>();

		private readonly TimedRoleModeRules tankMode = new TimedRoleModeRules(10.0);

		private readonly TimedRoleModeRules brawlerMode = new TimedRoleModeRules(30.0);

		private readonly Dictionary<PlayerAvatar, int> angryExpressionIndices = new Dictionary<PlayerAvatar, int>();

		private object angryModeStage;

		private object angryModeRoom;

		private bool angryModesFailed;

		private string assassinSelected;

		private string assassinError;

		private Harmony assassinPatches;

		private readonly AssassinRules assassinRules = new AssassinRules();

		private PlayerAvatar assassinAvatar;

		private object assassinRoom;

		private object assassinStage;

		private static readonly FieldInfo assassinVoiceOwner = AccessTools.Field(typeof(PlayerVoiceChat), "playerAvatar");

		private static readonly FieldInfo assassinAvatarNoise = AccessTools.Field(typeof(PlayerAvatar), "investigateTimer");

		private static readonly FieldInfo assassinVoiceNoise = AccessTools.Field(typeof(PlayerVoiceChat), "investigateTimer");

		private static readonly FieldInfo assassinCrawl = AccessTools.Field(typeof(PlayerAvatar), "isCrawling");

		private static readonly FieldInfo assassinCrouch = AccessTools.Field(typeof(PlayerAvatar), "isCrouching");

		private static readonly FieldInfo assassinTumble = AccessTools.Field(typeof(PlayerAvatar), "isTumbling");

		private readonly Stack<AssassinDamageScope> assassinDamageScopes = new Stack<AssassinDamageScope>();

		private static readonly FieldInfo assassinDamageOwner = AccessTools.Field(typeof(HurtCollider), "playerCausingHurt");

		private static readonly FieldInfo assassinDamageOverride = AccessTools.Field(typeof(HurtCollider), "playerCausingHurtOverride");

		private static readonly FieldInfo assassinEnemyHealthOwner = AccessTools.Field(typeof(EnemyHealth), "enemy");

		private static readonly FieldInfo assassinEnemyTarget = AccessTools.Field(typeof(Enemy), "TargetPlayerAvatar");

		private static readonly FieldInfo assassinEnemyVision = AccessTools.Field(typeof(Enemy), "Vision");

		private string birdSelected;

		private string birdError;

		private object birdRoom;

		private BirdBonus birdJump;

		private BirdBonus birdWings;

		private Harmony birdPatches;

		private ConfigEntry<int> birdWingsLevel;

		private ConfigEntry<float> birdAirTurn;

		private float birdNextTurn;

		private static readonly FieldInfo birdStats = AccessTools.Field(typeof(StatsManager), "dictionaryOfDictionaries");

		private static readonly FieldInfo birdTumble = AccessTools.Field(typeof(PlayerAvatar), "tumble");

		private static readonly FieldInfo birdGrounded = AccessTools.Field(typeof(PlayerAvatar), "isGrounded");

		private static readonly FieldInfo birdTumbling = AccessTools.Field(typeof(PlayerAvatar), "isTumbling");

		private static readonly FieldInfo birdInput = AccessTools.Field(typeof(PlayerAvatar), "InputDirectionRaw");

		private static readonly FieldInfo birdVelocity = AccessTools.Field(typeof(PlayerAvatar), "rbVelocityRaw");

		private static readonly FieldInfo birdFallTimer = AccessTools.Field(typeof(PlayerAvatar), "fallDamageResetTimer");

		private Harmony roleUpgradePatches;

		private readonly BirdFlightRules birdFlight = new BirdFlightRules();

		private ConfigEntry<float> birdFlightSeconds;

		private ConfigEntry<float> birdFlightSpeed;

		private ConfigEntry<float> birdFlightUpwardAngle;

		private PlayerAvatar birdFlightPlayer;

		private object birdFlightStage;

		private ItemUpgradePlayerTumbleWingsLogic birdFlyingLogic;

		private static readonly FieldInfo wingsFetched = AccessTools.Field(typeof(ItemUpgradePlayerTumbleWingsLogic), "fetchComplete");

		private static readonly FieldInfo wingsReady = AccessTools.Field(typeof(ItemUpgradePlayerTumbleWingsLogic), "lateStartDone");

		private static readonly FieldInfo wingsTimer = AccessTools.Field(typeof(ItemUpgradePlayerTumbleWingsLogic), "tumbleWingTimer");

		private static readonly FieldInfo tumbleTriggered = AccessTools.Field(typeof(PlayerTumble), "isPlayerInputTriggered");

		private static readonly FieldInfo tumbleForced = AccessTools.Field(typeof(PlayerTumble), "tumbleOverride");

		private static readonly PropertyInfo wingsPink = AccessTools.Property(typeof(PlayerAvatar), "upgradeTumbleWingsVisualsPink");

		private string bladerSelected;

		private string bladerError;

		private object bladerRoom;

		private object bladerStage;

		private PlayerAvatar bladerOwner;

		private Item bladerItem;

		private Harmony bladerPatches;

		private ConfigEntry<float> bladerDelay;

		private ConfigEntry<float> bladerOffset;

		private ConfigEntry<float> bladerSideOffset;

		private ConfigEntry<int> bladerDamage;

		private BladeItem bladerPrimary;

		private BladeItem bladerSecondary;

		private float bladerRetryAt;

		private long bladerSwing;

		private readonly BladerHistory<BladePose> bladerHistory = new BladerHistory<BladePose>();

		private readonly BladerHitRules bladerHits = new BladerHitRules();

		private readonly BladerContactRules bladerContacts = new BladerContactRules();

		private readonly BladerEnergyRules bladerEnergy = new BladerEnergyRules();

		private readonly BladerSway bladerSway = new BladerSway();

		private Vector3 bladerLateralOffset;

		private float bladerForwardDistance;

		private float bladerForwardVelocity;

		private double bladerForwardSampleAt = double.NaN;

		private BladePose bladerLast;

		private bool bladerHasLast;

		private BladePose bladerFollowTarget;

		private bool bladerHasFollowTarget;

		private Vector3 bladerLastCapturedPosition;

		private bool bladerHasCapturedPosition;

		private HurtCollider bladerDamageSource;

		private static readonly FieldInfo bladerNewSwing = AccessTools.Field(typeof(ItemMelee), "newSwing");

		private static readonly FieldInfo bladerHitTimer = AccessTools.Field(typeof(ItemMelee), "hitTimer");

		private static readonly FieldInfo bladerInventorySlot = AccessTools.Field(typeof(ItemEquippable), "inventorySpotIndex");

		private static readonly FieldInfo bladerForce = AccessTools.Field(typeof(HurtCollider), "applyForce");

		private static readonly FieldInfo bladerTorque = AccessTools.Field(typeof(HurtCollider), "applyTorque");

		private static readonly FieldInfo bladerEnemyBody = AccessTools.Field(typeof(EnemyRigidbody), "enemy");

		private static readonly FieldInfo bladerImpactDrain = AccessTools.Field(typeof(ItemMelee), "durabilityDrain");

		private static readonly FieldInfo bladerSprinting = AccessTools.Field(typeof(PlayerAvatar), "isSprinting");

		private static readonly MethodInfo bladerEnemyHit = AccessTools.Method(typeof(HurtCollider), "EnemyHurt", (Type[])null, (Type[])null);

		private readonly BladerCombatRules bladerCombat = new BladerCombatRules();

		private readonly TankRules bladerIncoming = new TankRules();

		private readonly HashSet<HurtCollider> bladerBoosting = new HashSet<HurtCollider>();

		private BladerSwordContact bladerHeldContact;

		private BladerSwordContact bladerFollowContact;

		private bool bladerSyncingDepleted;

		private static readonly FieldInfo bladerIsMelee = AccessTools.Field(typeof(PhysGrabObject), "isMelee");

		private static readonly FieldInfo bladerForceGrabPoint = AccessTools.Field(typeof(PhysGrabObject), "forceGrabPoint");

		private static readonly FieldInfo bladerMeleeGrabPoint = AccessTools.Field(typeof(ItemMelee), "forceGrabPoint");

		private static readonly FieldInfo bladerMeshHealthy = AccessTools.Field(typeof(ItemMelee), "meshHealthy");

		private static readonly FieldInfo bladerMeshBroken = AccessTools.Field(typeof(ItemMelee), "meshBroken");

		private readonly BladerEnergyCarry bladerCarry = new BladerEnergyCarry();

		private bool bladerEnergySealed;

		private readonly BladerForceScope bladerForceScope = new BladerForceScope();

		private static readonly FieldInfo bladerTakenNames = AccessTools.Field(typeof(StatsManager), "takenItemNames");

		private readonly BladerRecallRules bladerRecall = new BladerRecallRules();

		private readonly BladerExpressionRules bladerExpression = new BladerExpressionRules();

		private bool bladerExpressionAllowed;

		private const int BladerRecallExpression = 4;

		private static readonly FieldInfo bladerEquipping = AccessTools.Field(typeof(ItemEquippable), "isEquipping");

		private static readonly FieldInfo bladerUnequipping = AccessTools.Field(typeof(ItemEquippable), "isUnequipping");

		private static readonly MethodInfo bladerResetSwing = AccessTools.Method(typeof(ItemMelee), "ResetForFreshUnequip", (Type[])null, (Type[])null);

		private bool bladerLeavingStage;

		private string bladerTransportOwner;

		private int bladerTransportSlot = -1;

		private string bomberSelected;

		private string bomberError;

		private string bomberRoster;

		private object bomberRoom;

		private object bomberStage;

		private Harmony bomberPatches;

		private PrefabRef bomberClown;

		private GameObject bomberCarrier;

		private float bomberReadyAt;

		private float bomberRetryAt;

		private BomberDeath bomberDeath;

		private static readonly FieldInfo bomberPrefab = AccessTools.Field(typeof(ParticleScriptExplosion), "explosionPrefab");

		private static readonly FieldInfo bomberOwner = AccessTools.Field(typeof(ParticleScriptExplosion), "playerCausingHurtOverride");

		private static readonly FieldInfo bomberRuckus = AccessTools.Field(typeof(ParticleScriptExplosion), "playerHitFullRuckusOverride");

		private static readonly FieldInfo bomberParking = AccessTools.Field(typeof(AssetManager), "physDisabledPosition");

		private static readonly FieldInfo bomberHealth = AccessTools.Field(typeof(EnemyHealth), "healthCurrent");

		private static readonly FieldInfo bomberDead = AccessTools.Field(typeof(EnemyHealth), "dead");

		private static readonly FieldInfo bomberDying = AccessTools.Field(typeof(EnemyHealth), "deadImpulse");

		private static readonly FieldInfo bomberEnemyHealth = AccessTools.Field(typeof(Enemy), "Health");

		private static readonly FieldInfo bomberWipeDisabled = AccessTools.Field(typeof(RunManager), "allPlayersDeadCheckDisabled");

		private static readonly MethodInfo bomberRpc = typeof(PhotonView).GetMethod("RPC", new Type[3]
		{
			typeof(string),
			typeof(RpcTarget),
			typeof(object[])
		});

		private readonly BomberSupplyRules bomberSupplies = new BomberSupplyRules();

		private readonly List<BomberSupplyItem> bomberSupplyItems = new List<BomberSupplyItem>();

		private Harmony bomberSupplyPatches;

		private object bomberSupplyRoom;

		private object bomberSupplyStage;

		private bool bomberSupplyLeaving;

		private string bomberSupplyError;

		private Item bomberSupplyPrefab;

		private static readonly FieldInfo bomberSupplySpot = AccessTools.Field(typeof(ItemEquippable), "equippedSpot");

		private const int BrawlerPowerStrengthBonus = 5;

		private BirdBonus brawlerPowerStrength;

		private StatsManager brawlerPowerStats;

		private StatsManager brawlerPowerReadyStats;

		private PlayerAvatar brawlerPowerAvatar;

		private PlayerAvatar brawlerPowerReadyAvatar;

		private object brawlerPowerRoom;

		private object brawlerPowerStage;

		private object brawlerPowerReadyRoom;

		private object brawlerPowerReadyStage;

		private double brawlerPowerReadyAt;

		private bool brawlerPowerAvailable;

		private bool brawlerPowerRemoteDeltaAttempted;

		private Harmony brawlerPowerPatches;

		private readonly BudgetNoticeRules medicBudgetNotice = new BudgetNoticeRules();

		private readonly BudgetNoticeRules mechanicBudgetNotice = new BudgetNoticeRules();

		private object noticeBudgetStage;

		private readonly BudgetRechargeRules medicRecharge = new BudgetRechargeRules();

		private readonly BudgetRechargeRules mechanicRecharge = new BudgetRechargeRules();

		private double nextRepairRefillAttempt;

		private string burgerSelected;

		private string burgerError;

		private readonly BurgerStageCharge burgerInstantCharge = new BurgerStageCharge();

		private readonly BurgerRules burgerRules = new BurgerRules();

		private readonly BurgerGrabRules burgerGrabs = new BurgerGrabRules();

		private object burgerRoom;

		private object burgerMap;

		private BirdBonus burgerBattery;

		private static readonly FieldInfo burgerHeadConscious = AccessTools.Field(typeof(PlayerDeathHead), "spectated");

		private static readonly FieldInfo burgerCosmetics = AccessTools.Field(typeof(PlayerCosmetics), "cosmeticEquippedRaw");

		private static readonly FieldInfo burgerAssets = AccessTools.Field(typeof(MetaManager), "cosmeticAssets");

		private static readonly FieldInfo burgerHeld = AccessTools.Field(typeof(PhysGrabber), "grabbedPhysGrabObject");

		private static readonly FieldInfo burgerHeadSetup = AccessTools.Field(typeof(PlayerDeathHead), "setup");

		private static readonly FieldInfo burgerHeadTriggered = AccessTools.Field(typeof(PlayerDeathHead), "triggered");

		private string eaterSelected;

		private string eaterError;

		private object eaterRoom;

		private object eaterStage;

		private Harmony eaterPatches;

		private readonly EaterRules eaterRules = new EaterRules();

		private GameObject eaterCarrier;

		private ItemValuableBox eaterBox;

		private PhysGrabObject eaterPhys;

		private Item eaterItem;

		private float eaterReadyAt;

		private float eaterAbsorbUntil;

		private float eaterHeartbeat;

		private PlayerAvatar eaterEatingPlayer;

		private bool eaterLinked;

		private bool eaterExtracting;

		private bool eaterValueWrite;

		private bool eaterMoving;

		private int eaterLockedValue;

		private EaterRecovery eaterRecovery;

		private NativeEngineer engineer;

		private Harmony engineerPatches;

		private string engineerError;

		private readonly RepairRules repairRules = new RepairRules();

		private NativeRepair repair;

		private RoleShuffleBridge roleBridge;

		private string repairError;

		private string mechanicName = "None";

		private int selectedRole;

		internal const int RepairExpressionIndex = 3;

		private Harmony medicRevivalPatches;

		private string medicRevivalError;

		private readonly MedicPitRules medicPits = new MedicPitRules();

		private string meleeSpecialistSelected;

		private string meleeSpecialistError;

		private object meleeSpecialistRoom;

		private BirdBonus meleeSpecialistLaunch;

		private Harmony meleeSpecialistPatches;

		private readonly HashSet<HurtCollider> meleeSpecialistHits = new HashSet<HurtCollider>();

		private readonly Stack<PlayerAvatar> meleeSpecialistExplosions = new Stack<PlayerAvatar>();

		private readonly Stack<BrawlerAttack> meleeSpecialistExplosionAttacks = new Stack<BrawlerAttack>();

		private readonly BrawlerCombo meleeCombo = new BrawlerCombo();

		private object meleeComboStage;

		private object meleeComboAvatar;

		private static readonly FieldInfo comboHealth = AccessTools.Field(typeof(EnemyHealth), "healthCurrent");

		private static readonly FieldInfo comboEnemyHealth = AccessTools.Field(typeof(Enemy), "Health");

		private static readonly FieldInfo comboEnemyHasHealth = AccessTools.Field(typeof(Enemy), "HasHealth");

		private static readonly FieldInfo meleeSpecialistLastHolder = AccessTools.Field(typeof(PhysGrabObject), "lastPlayerGrabbing");

		private static readonly FieldInfo meleeSpecialistGrabTimer = AccessTools.Field(typeof(PhysGrabObject), "grabbedTimer");

		private static readonly FieldInfo meleeSpecialistTumbleSetup = AccessTools.Field(typeof(PlayerTumble), "setup");

		private string muscleSelected;

		private string muscleError;

		private object muscleRoom;

		private object muscleStage;

		private BirdBonus muscleStrength;

		private PlayerAvatar muscleAvatar;

		private StatsManager muscleStats;

		private double muscleReadyAt;

		private double muscleRejectAt;

		private double muscleReleaseAt;

		private int muscleReleaseObject;

		private bool muscleTransition;

		private Harmony musclePatches;

		private readonly MuscleRules muscleRules = new MuscleRules();

		private readonly MuscleOverchargeWindow muscleOvercharge = new MuscleOverchargeWindow();

		private readonly MuscleOverchargeSpeechCadence muscleOverchargeSpeech = new MuscleOverchargeSpeechCadence();

		private readonly Queue<int> muscleSpeechQueue = new Queue<int>();

		private static readonly FieldInfo muscleAvatarTumble = AccessTools.Field(typeof(PlayerAvatar), "tumble");

		private static readonly FieldInfo muscleTumblePlayer = AccessTools.Field(typeof(PlayerTumble), "playerAvatar");

		private static readonly FieldInfo muscleEnemyRequiredForce = AccessTools.Field(typeof(EnemyRigidbody), "grabForceNeeded");

		private static readonly FieldInfo muscleGrabForceMax = AccessTools.Field(typeof(PhysGrabber), "forceMax");

		private static readonly FieldInfo muscleDuckStunTimer = AccessTools.Field(typeof(EnemyStateStunned), "stunTimer");

		private static readonly FieldInfo muscleBodyEnemy = AccessTools.Field(typeof(EnemyRigidbody), "enemy");

		private static readonly FieldInfo muscleElsaStun = AccessTools.Field(typeof(Enemy), "StateStunned");

		private static readonly FieldInfo muscleElsaTeleport = AccessTools.Field(typeof(Enemy), "TeleportedTimer");

		private static readonly MethodInfo muscleElsaIsBig = AccessTools.Method(typeof(EnemyElsa), "IsBig", (Type[])null, (Type[])null);

		private EnemyElsa muscleHeldElsa;

		private PhysGrabObject muscleElsaObject;

		private PhysGrabber muscleElsaHolder;

		private MuscleElsaHold muscleElsaHold;

		private static readonly FieldInfo muscleReleaseTimer = AccessTools.Field(typeof(EnemyRigidbody), "grabReleaseRequestTimer");

		private static readonly FieldInfo muscleHasShake = AccessTools.Field(typeof(EnemyRigidbody), "hasShakeRelease");

		private static readonly FieldInfo muscleEnemyBody = AccessTools.Field(typeof(Enemy), "Rigidbody");

		[ThreadStatic]
		private static List<EnemyRigidbody> muscleMaintenance;

		private readonly Dictionary<PhysGrabber, MuscleReleaseNotice> muscleReleaseNotices = new Dictionary<PhysGrabber, MuscleReleaseNotice>();

		private static readonly FieldInfo muscleGrabTimeNeeded = AccessTools.Field(typeof(EnemyRigidbody), "grabTimeNeeded");

		private static readonly FieldInfo muscleTickState = AccessTools.Field(typeof(EnemyTick), "currentState");

		private static readonly MethodInfo muscleTickDeath = AccessTools.Method(typeof(EnemyHealth), "Death", new Type[1] { typeof(Vector3) }, (Type[])null);

		private readonly ConditionalWeakTable<EnemyTick, object> muscleKilledTicks = new ConditionalWeakTable<EnemyTick, object>();

		private readonly ConditionalWeakTable<EnemyTick, object> muscleAttachedTicks = new ConditionalWeakTable<EnemyTick, object>();

		private readonly ConditionalWeakTable<PhysGrabber, MuscleTickLink> muscleTickLinks = new ConditionalWeakTable<PhysGrabber, MuscleTickLink>();

		private string negotiatorSelected;

		private string negotiatorError;

		private object negotiatorRoom;

		private int negotiatorScene = int.MinValue;

		private Harmony negotiatorPatches;

		private readonly NegotiatorSpeechCooldown negotiatorSpeechCooldown = new NegotiatorSpeechCooldown();

		private readonly NegotiatorRules negotiatorRules = new NegotiatorRules();

		private readonly Dictionary<ExtractionPoint, int> negotiatorSpeech = new Dictionary<ExtractionPoint, int>();

		private static readonly FieldInfo negotiatorShopObject = AccessTools.Field(typeof(ShopKeeper), "itemReactObject");

		private static readonly FieldInfo negotiatorShopPlayer = AccessTools.Field(typeof(ShopKeeper), "itemReactPlayer");

		private static readonly FieldInfo negotiatorState = AccessTools.Field(typeof(ExtractionPoint), "currentState");

		private static readonly FieldInfo negotiatorPending = AccessTools.Field(typeof(ExtractionPoint), "stateSetTo");

		private static readonly FieldInfo negotiatorIsShop = AccessTools.Field(typeof(ExtractionPoint), "isShop");

		private static readonly FieldInfo negotiatorGoal = AccessTools.Field(typeof(ExtractionPoint), "haulGoal");

		private static readonly FieldInfo negotiatorAmount = AccessTools.Field(typeof(ExtractionPoint), "haulCurrent");

		private static readonly FieldInfo negotiatorGoalReady = AccessTools.Field(typeof(ExtractionPoint), "haulGoalFetched");

		private static readonly FieldInfo negotiatorVolume = AccessTools.Field(typeof(ExtractionPoint), "roomVolume");

		private static readonly FieldInfo negotiatorDelay = AccessTools.Field(typeof(ExtractionPoint), "successDelay");

		private static readonly MethodInfo negotiatorSetState = AccessTools.Method(typeof(ExtractionPoint), "StateSet", (Type[])null, (Type[])null);

		private static readonly FieldInfo negotiatorMoonPoint = AccessTools.Field(typeof(ExtractionHalloweenTower), "extractionPoint");

		private static readonly FieldInfo negotiatorMoonState = AccessTools.Field(typeof(ExtractionHalloweenTower), "currentState");

		private static readonly FieldInfo negotiatorMoonAccepted = AccessTools.Field(typeof(ExtractionHalloweenTower), "rewardAccepted");

		private static readonly FieldInfo negotiatorMoonUsed = AccessTools.Field(typeof(ExtractionHalloweenTower), "rewardUsed");

		private static readonly MethodInfo negotiatorMoonSetState = AccessTools.Method(typeof(ExtractionHalloweenTower), "StateSet", (Type[])null, (Type[])null);

		private AgentUpgradeLedger negotiatorStamina;

		private StatsManager negotiatorStaminaStats;

		private object negotiatorStaminaRoom;

		private object negotiatorStaminaStage;

		private PlayerAvatar negotiatorStaminaAvatar;

		private double negotiatorStaminaReadyAt;

		private Harmony negotiatorStaminaPatches;

		private bool negotiatorStaminaReady;

		public const string PluginId = "Guest-Role";

		internal const int ExpressionIndex = 3;

		internal static Plugin Current;

		private readonly GrantRules rules = new GrantRules();

		private readonly List<InputKey> blockHostInput = new List<InputKey>();

		private ConfigEntry<bool> modEnabled;

		private ConfigEntry<int> reviveHealth;

		private ConfigEntry<int> medicHealingLimit;

		private ConfigEntry<int> medicHealingHotkey;

		private int medicExpression = 3;

		private ConfigEntry<KeyboardShortcut> menuKey;

		private NativeContext native;

		private bool menuOpen;

		private bool hostReady;

		private bool mapReady;

		private int selectedRow;

		private float nextRosterRefresh;

		private float noticeUntil;

		private string selectedName = "None";

		private string notice = "";

		private List<PlayerAvatar> players = new List<PlayerAvatar>();

		private bool panelGrantRequested;

		private bool panelClearRequested;

		private string panelClearPlayerId;

		private object session;

		private readonly RoleMenuHold randomMenuHold = new RoleMenuHold();

		private Harmony drawbackDamagePatches;

		private bool drawbackDamageFailed;

		private readonly RoleDrawbackDamageScopes<PlayerAvatar, Enemy> drawbackDamageScopes = new RoleDrawbackDamageScopes<PlayerAvatar, Enemy>();

		private readonly Stack<DrawbackExplosionContext> drawbackExplosionSources = new Stack<DrawbackExplosionContext>();

		private static readonly FieldInfo drawbackProjectileSpawner = AccessTools.Field(typeof(SlowProjectile), "spawner");

		private static readonly FieldInfo drawbackProjectileOwner = AccessTools.Field(typeof(SlowProjectile), "playerCausingHurt");

		private static readonly FieldInfo drawbackExplosionOwner = AccessTools.Field(typeof(ParticlePrefabExplosion), "playerCausingHurt");

		private static readonly FieldInfo drawbackGrenadeActivator = AccessTools.Field(typeof(ItemGrenade), "activatorPlayerAvatar");

		private static readonly FieldInfo drawbackMineActivator = AccessTools.Field(typeof(ItemMine), "activatorPlayerAvatar");

		private readonly RoleExplanationWindow explanationWindow = new RoleExplanationWindow();

		private readonly Dictionary<string, PlayerAvatar> explanationPlayers = new Dictionary<string, PlayerAvatar>();

		private readonly List<ExplanationRequest> explanationRequests = new List<ExplanationRequest>();

		private object explanationSession;

		private bool panelExplainRequested;

		private static readonly string[] PanelRoles = new string[14]
		{
			"Medic", "Mechanic", "Tank", "Bird", "Brawler", "Burger", "Agent", "Trapper", "Bomber", "Blader",
			"Eater", "Zombie", "Muscle", "Negotiator"
		};

		private GUIStyle panelText;

		private GUIStyle panelTitle;

		private GUIStyle panelSmall;

		private GUIStyle panelButton;

		private GUIStyle panelRow;

		private Vector2 panelScroll;

		private int lastPanelRow = -1;

		private Texture2D panelPointer;

		private readonly List<RoleAnnouncement> roleAnnouncements = new List<RoleAnnouncement>();

		private static readonly FieldInfo roleVoiceChat = AccessTools.Field(typeof(PlayerAvatar), "voiceChat");

		private readonly RoleVulnerabilityRules roleVulnerability = new RoleVulnerabilityRules();

		private string vulnerabilityBird;

		private string vulnerabilityMechanic;

		private string vulnerabilityBomber;

		private readonly TankRules tankRules = new TankRules();

		private readonly TankHitScope tankHitScope = new TankHitScope();

		private readonly List<TankDamageContext> tankContexts = new List<TankDamageContext>();

		private readonly Dictionary<PlayerAvatar, TankRevival> tankRevivals = new Dictionary<PlayerAvatar, TankRevival>();

		private readonly Dictionary<PlayerAvatar, int> tankWrites = new Dictionary<PlayerAvatar, int>();

		private Harmony tankPatches;

		private string tankError;

		private string tankName = "None";

		private string tankLastResult = "No damage observed yet.";

		private float nextTankDiagnostic;

		private ConfigEntry<bool> tankLogging;

		private bool tankWriting;

		private object tankStage;

		private object tankRoom;

		private PlayerAvatar maxAvatar;

		private int maxOriginal;

		private int maxUpgrade;

		private int maxApplied;

		private object maxRoom;

		private static readonly MethodInfo tankRpc = typeof(PhotonView).GetMethod("RPC", new Type[3]
		{
			typeof(string),
			typeof(RpcTarget),
			typeof(object[])
		});

		private static readonly FieldInfo headTimer = AccessTools.Field(typeof(PlayerDeathHead), "triggeredTimer");

		private static readonly FieldInfo healthReady = AccessTools.Field(typeof(PlayerHealth), "healthSet");

		private static readonly FieldInfo detectionOnly = AccessTools.Field(typeof(HurtCollider), "detectionOnly");

		private static readonly FieldInfo ignoreLocal = AccessTools.Field(typeof(HurtCollider), "ignoreLocalPlayer");

		private readonly TankDirectRules tankDirectDamage = new TankDirectRules();

		private readonly TankInvincibilityRules tankModeDamage = new TankInvincibilityRules();

		private readonly Dictionary<PlayerAvatar, TankModeRevival> tankModeRevivals = new Dictionary<PlayerAvatar, TankModeRevival>();

		private HurtCollider[] tankModePits = Array.Empty<HurtCollider>();

		private double tankModeNextPitScan;

		private static readonly FieldInfo tankModeCollider = AccessTools.Field(typeof(HurtCollider), "Collider");

		private static readonly FieldInfo tankModeHeadTriggered = AccessTools.Field(typeof(PlayerDeathHead), "triggered");

		private static readonly FieldInfo tankModeHeadPosition = AccessTools.Field(typeof(PlayerDeathHead), "triggeredPosition");

		private static readonly FieldInfo tankModeWipeDisabled = AccessTools.Field(typeof(RunManager), "allPlayersDeadCheckDisabled");

		private string trapperSelected;

		private string trapperError;

		private object trapperRoom;

		private object trapperStage;

		private PlayerAvatar trapperAvatar;

		private readonly TrapperRules trapperRules = new TrapperRules();

		private readonly TrapperMineLedger<GameObject> trapperMines = new TrapperMineLedger<GameObject>();

		private Harmony trapperPatches;

		private Item trapperItem;

		private readonly HashSet<string> trapperPlacedNames = new HashSet<string>();

		private static readonly FieldInfo trapperCrouch = AccessTools.Field(typeof(PlayerAvatar), "isCrouching");

		private static readonly FieldInfo trapperCrawl = AccessTools.Field(typeof(PlayerAvatar), "isCrawling");

		private static readonly FieldInfo trapperTumble = AccessTools.Field(typeof(PlayerAvatar), "isTumbling");

		private static readonly FieldInfo trapperGrounded = AccessTools.Field(typeof(PlayerAvatar), "isGrounded");

		private static readonly FieldInfo trapperSliding = AccessTools.Field(typeof(PlayerAvatar), "isSliding");

		private static readonly MethodInfo trapperSetState = AccessTools.Method(typeof(ItemMine), "StateSet", (Type[])null, (Type[])null);

		private static readonly MethodInfo trapperSetActivator = AccessTools.Method(typeof(ItemMine), "SetActivator", (Type[])null, (Type[])null);

		private static readonly FieldInfo trapperMineState = AccessTools.Field(typeof(ItemMine), "state");

		private static readonly FieldInfo trapperPhysSpawned = AccessTools.Field(typeof(PhysGrabObject), "spawned");

		private static readonly FieldInfo trapperInstanceName = AccessTools.Field(typeof(ItemAttributes), "instanceName");

		private PendingTrap pendingTrap;

		private double trapperRetryAt;

		private const string TrapperChargeStoreKey = "guestRoleTrapperRemainingV1";

		private static readonly FieldInfo trapperChargeDictionaries = AccessTools.Field(typeof(StatsManager), "dictionaryOfDictionaries");

		private static readonly FieldInfo trapperChargeIgnoredDictionaries = AccessTools.Field(typeof(StatsManager), "doNotSaveTheseDictionaries");

		private readonly List<TrapperSourceDepletion> trapperSourceDepletions = new List<TrapperSourceDepletion>();

		private int trapperSearchDepth;

		private static readonly FieldInfo trapperPhysEnemy = AccessTools.Field(typeof(PhysGrabObject), "isEnemy");

		private static readonly FieldInfo trapperPhysPlayer = AccessTools.Field(typeof(PhysGrabObject), "isPlayer");

		private static readonly FieldInfo trapperHeldPhys = AccessTools.Field(typeof(PhysGrabber), "grabbedPhysGrabObject");

		private static readonly FieldInfo trapperBookTarget = AccessTools.Field(typeof(ChompBookTrap), "targetTransform");

		private double trapperNextBlockLog;

		private readonly Dictionary<ItemMine, TrapperMineCarry> trapperMineCarries = new Dictionary<ItemMine, TrapperMineCarry>();

		private double trapperCarryPruneAt;

		private double trapperCarryErrorAt;

		private readonly HashSet<TrapperMineCollisionGuard> trapperMineGuards = new HashSet<TrapperMineCollisionGuard>();

		private TrapperSupplyRules trapperSupply = new TrapperSupplyRules();

		private double trapperSupplyReadyAt = double.NaN;

		private BoxCollider[] trapperTruckBoxes;

		private static readonly FieldInfo upgradeToggleDisabled = AccessTools.Field(typeof(ItemToggle), "disabled");

		private static readonly FieldInfo upgradeRecipientSpawned = AccessTools.Field(typeof(PlayerAvatar), "spawned");

		private readonly List<UpgradeRestrictionEntry> upgradeRestrictions = new List<UpgradeRestrictionEntry>();

		private Harmony upgradeRestrictionPatches;

		private bool upgradeRestrictionsReady;

		private object upgradeRestrictionRoom;

		private string upgradeRestrictedTank;

		private string upgradeRestrictedEater;

		private double nextUpgradeRestrictionScan;

		private string zombieSelected;

		private string zombieError;

		private object zombieRoom;

		private object zombieStage;

		private BirdBonus zombieBattery;

		private PlayerDeathHead zombieHead;

		private ZombieHeadContact zombieContact;

		private readonly ZombieRules zombieRules = new ZombieRules();

		private ConfigEntry<float> zombieImpactSpeed;

		private static readonly FieldInfo zombiePreviousVelocity = AccessTools.Field(typeof(PhysGrabObjectImpactDetector), "previousPreviousVelocityRaw");

		private Harmony zombieJumpPatches;

		private static readonly FieldInfo zombieJumpMaximum = AccessTools.Field(typeof(PlayerDeathHead), "spectatedJumpChargeAmountMax");

		private bool AgentUpgradeAuthority
		{
			get
			{
				if (native != null && Object.op_Implicit((Object)(object)GameManager.instance) && SemiFunc.IsMasterClientOrSingleplayer())
				{
					return native.Room != null;
				}
				return false;
			}
		}

		private bool AgentUpgradeLedgerCurrent
		{
			get
			{
				if (agentUpgradeLedgers.Count > 0 && Object.op_Implicit((Object)(object)agentUpgradeStats) && agentUpgradeStats == StatsManager.instance)
				{
					return agentUpgradeLedgers.All((AgentUpgradeLedger l) => l.Values == AgentUpgradeValues(agentUpgradeStats, l.Upgrade));
				}
				return false;
			}
		}

		private bool AngryModeGameplay
		{
			get
			{
				//IL_0082: Unknown result type (might be due to invalid IL or missing references)
				//IL_0088: Invalid comparison between Unknown and I4
				//IL_008f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0095: Invalid comparison between Unknown and I4
				if (((Behaviour)this).enabled && hostReady && modEnabled.Value && Object.op_Implicit((Object)(object)RunManager.instance) && SemiFunc.RunIsLevel() && agentUpgradeRestarting != null && !(bool)agentUpgradeRestarting.GetValue(RunManager.instance) && Object.op_Implicit((Object)(object)LevelGenerator.Instance) && LevelGenerator.Instance.Generated && Object.op_Implicit((Object)(object)GameDirector.instance))
				{
					if ((int)GameDirector.instance.currentState != 2)
					{
						return (int)GameDirector.instance.currentState == 7;
					}
					return true;
				}
				return false;
			}
		}

		private bool BladerActive
		{
			get
			{
				if (((Behaviour)this).enabled && hostReady && BladerSceneReady && modEnabled.Value && bladerError == null && bladerSelected != null && bladerRoom == session)
				{
					return bladerStage == LevelGenerator.Instance;
				}
				return false;
			}
		}

		private bool BladerSceneReady
		{
			get
			{
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0043: Invalid comparison between Unknown and I4
				if (!bladerLeavingStage && Object.op_Implicit((Object)(object)RunManager.instance) && Object.op_Implicit((Object)(object)GameDirector.instance) && Object.op_Implicit((Object)(object)LevelGenerator.Instance) && LevelGenerator.Instance.Generated && (int)GameDirector.instance.currentState == 2)
				{
					if (!SemiFunc.RunIsLevel())
					{
						return SemiFunc.RunIsLobby();
					}
					return true;
				}
				return false;
			}
		}

		private bool BomberActive
		{
			get
			{
				//IL_0059: Unknown result type (might be due to invalid IL or missing references)
				//IL_005f: Invalid comparison between Unknown and I4
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_006c: Invalid comparison between Unknown and I4
				if (((Behaviour)this).enabled && hostReady && modEnabled.Value && Object.op_Implicit((Object)(object)LevelGenerator.Instance) && LevelGenerator.Instance.Generated && SemiFunc.RunIsLevel() && Object.op_Implicit((Object)(object)GameDirector.instance) && ((int)GameDirector.instance.currentState == 2 || (int)GameDirector.instance.currentState == 7) && bomberError == null && bomberSelected != null && Object.op_Implicit((Object)(object)GameManager.instance) && SemiFunc.IsMasterClientOrSingleplayer() && session == native.Room && bomberStage == LevelGenerator.Instance)
				{
					return bomberRoom == session;
				}
				return false;
			}
		}

		private bool BrawlerPowerLedgerCurrent
		{
			get
			{
				if (brawlerPowerStrength != null && Object.op_Implicit((Object)(object)brawlerPowerStats) && (Object)(object)brawlerPowerStats == (Object)(object)StatsManager.instance)
				{
					return brawlerPowerStrength.Values == brawlerPowerStats.playerUpgradeStrength;
				}
				return false;
			}
		}

		private bool EaterActive
		{
			get
			{
				if (((Behaviour)this).enabled && hostReady && modEnabled.Value && eaterError == null && eaterSelected != null && Object.op_Implicit((Object)(object)GameManager.instance) && SemiFunc.IsMasterClientOrSingleplayer() && Object.op_Implicit((Object)(object)LevelGenerator.Instance) && LevelGenerator.Instance.Generated && SemiFunc.RunIsLevel() && eaterStage == LevelGenerator.Instance)
				{
					return eaterRoom == session;
				}
				return false;
			}
		}

		private Vector3 EaterParking
		{
			get
			{
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				if (!Object.op_Implicit((Object)(object)AssetManager.instance))
				{
					return new Vector3(0f, -1000f, 0f);
				}
				return EV<Vector3>(AssetManager.instance, "physDisabledPosition");
			}
		}

		private bool EngineerActive
		{
			get
			{
				//IL_0092: Unknown result type (might be due to invalid IL or missing references)
				//IL_0098: Invalid comparison between Unknown and I4
				if (((Behaviour)this).enabled && modEnabled != null && modEnabled.Value && Object.op_Implicit((Object)(object)GameManager.instance) && SemiFunc.IsMasterClientOrSingleplayer() && native.Room != null && session == native.Room && Object.op_Implicit((Object)(object)RunManager.instance) && Object.op_Implicit((Object)(object)GameDirector.instance) && Object.op_Implicit((Object)(object)LevelGenerator.Instance) && LevelGenerator.Instance.Generated && SemiFunc.RunIsLevel())
				{
					return (int)GameDirector.instance.currentState == 2;
				}
				return false;
			}
		}

		internal RoleShuffleBridge RepairBridge => roleBridge;

		private bool MeleeSpecialistAuthority
		{
			get
			{
				if (((Behaviour)this).enabled && hostReady && modEnabled.Value && meleeSpecialistError == null && Object.op_Implicit((Object)(object)GameManager.instance) && SemiFunc.IsMasterClientOrSingleplayer())
				{
					return session == native.Room;
				}
				return false;
			}
		}

		private bool MuscleAuthority
		{
			get
			{
				if (muscleError == null && ((Behaviour)this).enabled && hostReady && modEnabled.Value && Object.op_Implicit((Object)(object)GameManager.instance) && SemiFunc.IsMasterClientOrSingleplayer() && native != null && muscleRoom == native.Room)
				{
					return !muscleTransition;
				}
				return false;
			}
		}

		private bool MuscleLedgerCurrent
		{
			get
			{
				if (muscleStrength != null && Object.op_Implicit((Object)(object)muscleStats) && (Object)(object)muscleStats == (Object)(object)StatsManager.instance)
				{
					return muscleStrength.Values == muscleStats.playerUpgradeStrength;
				}
				return false;
			}
		}

		private bool NegotiatorAuthority
		{
			get
			{
				if (negotiatorError == null && ((Behaviour)this).enabled && hostReady && modEnabled.Value && native != null && Object.op_Implicit((Object)(object)GameManager.instance))
				{
					return SemiFunc.IsMasterClientOrSingleplayer();
				}
				return false;
			}
		}

		private bool NegotiatorStaminaLedgerCurrent
		{
			get
			{
				if (negotiatorStamina != null && Object.op_Implicit((Object)(object)negotiatorStaminaStats) && negotiatorStaminaStats == StatsManager.instance)
				{
					return negotiatorStamina.Values == negotiatorStaminaStats.playerUpgradeStamina;
				}
				return false;
			}
		}

		private string MedicKeyLabel
		{
			get
			{
				if (medicHealingHotkey.Value != -1)
				{
					return medicHealingHotkey.Value + " / Expression" + medicExpression;
				}
				return "Disabled";
			}
		}

		private PlayerAvatar HighlightedPlayer
		{
			get
			{
				if (selectedRow < 0 || selectedRow >= players.Count)
				{
					return null;
				}
				return players[selectedRow];
			}
		}

		private string HighlightedPlayerId
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)HighlightedPlayer))
				{
					return null;
				}
				return native.Id(HighlightedPlayer);
			}
		}

		private string RoleName
		{
			get
			{
				if (selectedRole != 0)
				{
					if (selectedRole != 1)
					{
						if (selectedRole != 2)
						{
							if (selectedRole != 3)
							{
								if (selectedRole != 4)
								{
									if (selectedRole != 5)
									{
										if (selectedRole != 6)
										{
											if (selectedRole != 7)
											{
												if (selectedRole != 8)
												{
													if (selectedRole != 9)
													{
														if (selectedRole != 10)
														{
															if (selectedRole != 11)
															{
																if (selectedRole != 12)
																{
																	return "Negotiator";
																}
																return "Muscle";
															}
															return "Zombie";
														}
														return "Eater";
													}
													return "Blader";
												}
												return "Bomber";
											}
											return "Trapper";
										}
										return "Agent";
									}
									return "Burger";
								}
								return "Brawler";
							}
							return "Bird";
						}
						return "Tank";
					}
					return "Mechanic";
				}
				return "Medic";
			}
		}

		private int ConfiguredReviveHealth => Math.Max(1, Math.Min(1000, reviveHealth.Value));

		private bool DrawbackDamageAuthority
		{
			get
			{
				if (!drawbackDamageFailed && ((Behaviour)this).enabled && hostReady && modEnabled.Value && Object.op_Implicit((Object)(object)GameManager.instance) && SemiFunc.IsMasterClientOrSingleplayer())
				{
					return session == native.Room;
				}
				return false;
			}
		}

		private bool ExplanationJapanese => RoleExplanationText.IsJapanese(SemiFunc.LocaleGetCode());

		private string RoleDescription
		{
			get
			{
				if (selectedRole != 0)
				{
					if (selectedRole != 1)
					{
						if (selectedRole != 2)
						{
							if (selectedRole != 3)
							{
								if (selectedRole != 4)
								{
									if (selectedRole != 5)
									{
										if (selectedRole != 6)
										{
											if (selectedRole != 7)
											{
												if (selectedRole != 8)
												{
													if (selectedRole != 9)
													{
														if (selectedRole != 10)
														{
															if (selectedRole != 11)
															{
																if (selectedRole != 12)
																{
																	return "Negotiator: personally hand a shop item to the shopkeeper. Each of the three shop verdicts has a 53.33% success chance (vanilla 33.33% + 20 percentage points). Native discount amount and three-attempt shop limit remain. While alive inside a funded extraction, prevents collection until leaving. Also holds pending Moon evaluation/scans inside the frame, even below quota; accepted rewards are unchanged. Taxman lines have a 300s per-player cooldown. Discount/extraction abilities do not work while dead. One purchased Stamina upgrade is inactive (-10 maximum stamina, never below the unupgraded base); restored when the role is removed.";
																}
																return "Muscle: Strength +20 above purchases; after 30s accumulated grabbing of enemies requiring at least 10 Strength upgrades to grab solo or Big/Wide/Tall/VeryTall valuables, bonus falls by 2/s to 0. Before fatigue, empty hands for 5s restores 1s of holding allowance per second. Other held objects pause the count without restoring it. After 30s at zero bonus, regains 2/s to +20. Melee enemy damage x1.2 only before fatigue or after full recovery. Grabbing a Tick before it attaches kills it. Apex Predator grab refreshes a 2s stun while not fatigued. No grab-to-stun delay once native grab-force conditions pass; native stun restrictions remain. Enemy shake/attack grab releases do not release Muscle; teleport/despawn still release. Ranged, trap and throwable weapons may be held in shops and the travel truck, but cannot be stored in inventory. They are forcibly released elsewhere. Overcharge launch is suppressed and tumble cancelled; release/FX remain. Guest damage cancellation is best-effort due to network delay.";
															}
															return "Zombie: Death Head Battery +100; jump charge speed x2.4 (same maximum range). While dead: enemy contact deals 20 damage (strong impact: 30 + 2s stun, except Clown/Trudge); then enemies within 0.5m of the head take 5 damage every 2s. Allies holding the head lose 1 HP every 2s.";
														}
														return "Eater: hold a cargo-bike-sized valuable (Tiny/Small), activate joy (0 / Expression6) to eat. Stored total is spoken in chat. Capacity: $30,000; over capacity: I'm stuffed. Stand on extraction to add its value; after being crushed, revive at the previous HP when the tube rises. Cannot use new Strength upgrades.";
													}
													return "Blader: owner-only DoubleSword with a delayed second blade and 50% energy consumption. At zero energy both swords look broken but still swing for 1 damage per hit. Close eyes (8 / Expression4) to recall the sword. Ranged enemy damage -10%.";
												}
												return "Bomber: death triggers a clown-doll explosion (300 base enemy damage; 100 player damage). Killing an enemy directly with this explosion revives you after 3s at 1 HP. No ally-distance exclusion or per-stage use limit. Starts each stage with one regular grenade (waits for a free inventory slot); the supplied grenade expires at scene exit. Incoming HP loss +15%.";
											}
											return "Trapper: look down at least 70 degrees while standing, then crouch and keep looking down for 0.5s: armed copy of the leftmost inventory mine 0.3m ahead (6 uses per original trap, retained across shops/stages; no recharge; original disappears after use 6; remaining count spoken; copies cannot be stored). If no mine is in the truck at stage start, one normal stun mine is supplied in the truck. Native traps ignore you as a detection target. Stand again to repeat. Ranged enemy damage -10%.";
										}
										return "Agent: radar only while your map is open; scans every 1s (25m nearby entry / named direction on each enemy's 15m entry; re-arm at 16m). Gnomes or Bangers within 5m of the notified enemy share the notice. After a direction notice, notified enemies are excluded for 10s. Firearms deal x1.1 enemy damage; movement/voice/TTS do not alert enemies; 2x visual recognition time. Unaware target takes base damage x1.5, replacing the firearm bonus. ALL abilities and purchased Strength/Range/Throw/Speed bonuses pause while carrying 3+ items (including a held inventory item); restored at 2 or fewer. Other upgrades stay active.";
									}
									return "Burger: equip the Burger head-top mesh (bottom optional). Tumble + hold 8: first eligible grab per stage heals 50 HP (15 HP cost); held allies heal 10 HP/1s (3 HP cost). Costs can kill Burger. Battery level 30. Conscious death head heals holders 3 HP/1s.";
								}
								return "Brawler: +1 Tumble Launch level; tumble attacks deal 30 damage and stun enemies for 2s; melee combo x1.1 / x1.2 / x1.3; next hit within 3s, then restart (rounded). Angry face: Strength +5 for 30s, 10-minute cooldown. Ranged enemy damage -10%.";
							}
							return "Bird: +1 extra jump, Wings level " + birdWingsLevel.Value + ", no fall damage (pits excluded). Tumble in midair + forward: camera-directed flight, landing recharges. Default flight duration 6s. Incoming HP loss +5%.";
						}
						return "Tank: restore allies' enemy damage within 8m; pay 50% yourself (rounded up), stopping at 1 HP. Direct HP damage -15% (post-hit correction; taken damage rounded up; pits excluded). Angry face: 10s HP correction/revival (pits excluded), zero cover cost; 10-minute cooldown. Outside the mode, at 1 HP cover stops. Lethal hits use corrective revival. Cannot use new Speed upgrades.";
					}
					return "Mechanic: directly hold valuables + hold 7 / Expression3 to repair 2%/s (50%/stage). Repair allowance fully recharges 10 minutes after exhaustion. Engineer effect suppression stays automatic. Carts do not repair their contents. Incoming HP loss +5%.";
				}
				return $"Medic: auto revive nearest fallen ally within 3m at {ConfiguredReviveHealth} HP, {rules.RevivesRemaining}/1 stock; 10-minute cooldown after use, one stock at stage start. Wait 5s after the head/ally last falls into a death pit. Hold {MedicKeyLabel}: 5 HP per ally per 2s within 5m, {rules.HealingRemaining}/{rules.HealingLimit} HP left. Healing allowance fully recharges 10 minutes after exhaustion. Weapon enemy damage -5%.";
			}
		}

		private string PanelError
		{
			get
			{
				object obj;
				if (selectedRole != 0)
				{
					if (selectedRole != 1)
					{
						if (selectedRole != 2)
						{
							if (selectedRole != 3)
							{
								if (selectedRole != 4)
								{
									if (selectedRole != 5)
									{
										if (selectedRole != 6)
										{
											if (selectedRole != 7)
											{
												if (selectedRole != 8)
												{
													if (selectedRole != 9)
													{
														if (selectedRole != 10)
														{
															if (selectedRole != 11)
															{
																if (selectedRole != 12)
																{
																	return negotiatorError;
																}
																return muscleError;
															}
															return zombieError;
														}
														return eaterError;
													}
													return bladerError;
												}
												return bomberError;
											}
											return trapperError;
										}
										return assassinError;
									}
									return burgerError;
								}
								return meleeSpecialistError;
							}
							return birdError;
						}
						return tankError;
					}
					obj = repairError;
					if (obj == null)
					{
						return engineerError;
					}
				}
				else
				{
					obj = null;
				}
				return (string)obj;
			}
		}

		private bool TankAuthority
		{
			get
			{
				if (((Behaviour)this).enabled && hostReady && Object.op_Implicit((Object)(object)GameManager.instance) && SemiFunc.IsMasterClientOrSingleplayer())
				{
					return session == native.Room;
				}
				return false;
			}
		}

		private bool TankModeDamageGate
		{
			get
			{
				if (!angryModesFailed && AngryModeGameplay)
				{
					return tankMode.IsActive(tankRules.Selected, Time.timeAsDouble);
				}
				return false;
			}
		}

		private bool TankActive
		{
			get
			{
				//IL_0049: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: Invalid comparison between Unknown and I4
				if (TankAuthority && modEnabled.Value && tankError == null && Object.op_Implicit((Object)(object)RunManager.instance) && SemiFunc.RunIsLevel() && Object.op_Implicit((Object)(object)GameDirector.instance))
				{
					if (!mapReady || (int)GameDirector.instance.currentState != 2)
					{
						return TankModeDamageGate;
					}
					return true;
				}
				return false;
			}
		}

		private bool TankResistanceActive
		{
			get
			{
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0034: Invalid comparison between Unknown and I4
				if (TankAuthority && modEnabled.Value && tankError == null && Object.op_Implicit((Object)(object)GameDirector.instance))
				{
					if ((int)GameDirector.instance.currentState != 2 && !TankModeDamageGate)
					{
						return AngryModeGameplay;
					}
					return true;
				}
				return false;
			}
		}

		private bool UpgradeRestrictionAuthority
		{
			get
			{
				if (native != null && Object.op_Implicit((Object)(object)GameManager.instance) && SemiFunc.IsMasterClientOrSingleplayer())
				{
					return native.Room != null;
				}
				return false;
			}
		}

		private bool ZombieActive
		{
			get
			{
				if (((Behaviour)this).enabled && hostReady && mapReady && modEnabled.Value && zombieError == null && zombieSelected != null && Object.op_Implicit((Object)(object)GameManager.instance) && SemiFunc.IsMasterClientOrSingleplayer())
				{
					return zombieRoom == native.Room;
				}
				return false;
			}
		}

		private void InitializeAgentEnergyPatches()
		{
			//IL_0051: 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_0073: Expected O, but got Unknown
			//IL_0073: Expected O, but got Unknown
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			//IL_00c2: Expected O, but got Unknown
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Expected O, but got Unknown
			//IL_0111: Expected O, but got Unknown
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Expected O, but got Unknown
			//IL_0160: Expected O, but got Unknown
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Expected O, but got Unknown
			if (agentEnergyBars == null || meleeSpecialistLastHolder == null)
			{
				throw new MissingFieldException("Agent firearm energy API changed.");
			}
			assassinPatches.Patch((MethodBase)AccessTools.Method(typeof(ItemGun), "ShootRPC", (Type[])null, (Type[])null), new HarmonyMethod(typeof(AgentEnergyHooks), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(AgentEnergyHooks), "Finalizer", (Type[])null), (HarmonyMethod)null);
			assassinPatches.Patch((MethodBase)AccessTools.Method(typeof(ItemGun), "StateShooting", (Type[])null, (Type[])null), new HarmonyMethod(typeof(AgentEnergyHooks), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(AgentEnergyHooks), "Finalizer", (Type[])null), (HarmonyMethod)null);
			assassinPatches.Patch((MethodBase)AccessTools.Method(typeof(ItemCartCannon), "ShootLogic", (Type[])null, (Type[])null), new HarmonyMethod(typeof(AgentEnergyHooks), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(AgentEnergyHooks), "Finalizer", (Type[])null), (HarmonyMethod)null);
			assassinPatches.Patch((MethodBase)AccessTools.Method(typeof(ItemCartLaser), "StateGoingBack", (Type[])null, (Type[])null), new HarmonyMethod(typeof(AgentEnergyHooks), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(AgentEnergyHooks), "Finalizer", (Type[])null), (HarmonyMethod)null);
			assassinPatches.Patch((MethodBase)AccessTools.Method(typeof(ItemBattery), "RemoveFullBar", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Plugin), "AgentEnergyBarsPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static void AgentEnergyBarsPrefix(ItemBattery __instance, ref int _bars)
		{
			Plugin current = Current;
			if (!Object.op_Implicit((Object)(object)current) || _bars <= 0 || current.agentEnergyScopes.Count == 0)
			{
				return;
			}
			AgentEnergyScope agentEnergyScope = current.agentEnergyScopes.Peek();
			if (agentEnergyScope.Reduced && !((Object)(object)agentEnergyScope.Battery != (Object)(object)__instance) && current.IsAssassin(agentEnergyScope.Player) && !SemiFunc.RunIsShop() && (int)agentEnergyBars.GetValue(__instance) > 0)
			{
				_bars = current.agentEnergyDebts.GetValue(__instance, (ItemBattery _) => new AgentEnergyRules()).SpendBars(_bars);
			}
		}

		private static void InitializeAgentInventory()
		{
			if (agentInventoryHeld == null || agentInventoryHeld.FieldType != typeof(PhysGrabObject) || agentInventoryInstanceName == null || agentInventoryInstanceName.FieldType != typeof(string) || agentInventoryState == null || agentInventoryState.FieldType != typeof(ItemState) || agentInventoryUnequipping == null || agentInventoryUnequipping.FieldType != typeof(bool) || agentInventoryForcedUnequip == null || agentInventoryForcedUnequip.FieldType != typeof(bool) || agentInventoryStateRpc == null)
			{
				throw new MissingFieldException("Agent carried-item API changed.");
			}
		}

		private void InitializeAgentInventoryCompatibility()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			assassinPatches.Patch((MethodBase)agentInventoryStateRpc, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "AgentInventoryStatePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			MethodInfo methodInfo = AccessTools.Method("REPOJP.StageRoles.UtilityRoleRuntime:SuppressPlayerInvestigations", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				assassinPatches.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Plugin), "AgentNinjaNoisePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static bool AgentNinjaNoisePrefix(PlayerAvatar player)
		{
			if (Object.op_Implicit((Object)(object)Current))
			{
				return !Current.HasAgentRole(player);
			}
			return true;
		}

		private static void AgentInventoryStatePostfix(ItemEquippable __instance, int state)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			Plugin current = Current;
			if (!Object.op_Implicit((Object)(object)current) || !Object.op_Implicit((Object)(object)__instance))
			{
				return;
			}
			if (state != 3 || (int)(ItemState)agentInventoryState.GetValue(__instance) != 3 || (bool)agentInventoryForcedUnequip.GetValue(__instance))
			{
				current.agentPendingDraws.Remove(__instance);
				return;
			}
			PlayerAvatar ownerPlayerAvatar = __instance.GetOwnerPlayerAvatar();
			if (Object.op_Implicit((Object)(object)ownerPlayerAvatar) && current.HasAgentRole(ownerPlayerAvatar))
			{
				current.agentPendingDraws[__instance] = new AgentPendingDraw
				{
					Owner = ownerPlayerAvatar,
					Room = current.native.Room
				};
			}
		}

		private int AgentPendingDrawCount(PlayerAvatar player, ItemEquippable held)
		{
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Invalid comparison between Unknown and I4
			int num = 0;
			agentFinishedDraws.Clear();
			foreach (KeyValuePair<ItemEquippable, AgentPendingDraw> agentPendingDraw in agentPendingDraws)
			{
				ItemEquippable key = agentPendingDraw.Key;
				PlayerAvatar owner = agentPendingDraw.Value.Owner;
				int num2;
				object obj;
				if (Object.op_Implicit((Object)(object)key) && Object.op_Implicit((Object)(object)owner) && ((Component)key).gameObject.activeInHierarchy && agentPendingDraw.Value.Room == native.Room && HasAgentRole(owner) && (Object)(object)key.GetOwnerPlayerAvatar() == (Object)(object)owner && !key.IsEquipped())
				{
					num2 = ((!(bool)agentInventoryForcedUnequip.GetValue(key)) ? 1 : 0);
					if (num2 != 0)
					{
						obj = ((Component)key).GetComponent<PhysGrabObject>();
						goto IL_00b6;
					}
				}
				else
				{
					num2 = 0;
				}
				obj = null;
				goto IL_00b6;
				IL_00b6:
				PhysGrabObject val = (PhysGrabObject)obj;
				bool flag = Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)owner.physGrabber) && val.playerGrabbing != null && val.playerGrabbing.Contains(owner.physGrabber);
				bool flag2 = num2 != 0 && ((int)(ItemState)agentInventoryState.GetValue(key) == 3 || (bool)agentInventoryUnequipping.GetValue(key));
				if (num2 == 0 || (!flag2 && !flag) || (Object)(object)key == (Object)(object)held)
				{
					agentFinishedDraws.Add(key);
				}
				else if ((Object)(object)owner == (Object)(object)player)
				{
					num++;
				}
			}
			foreach (ItemEquippable agentFinishedDraw in agentFinishedDraws)
			{
				agentPendingDraws.Remove(agentFinishedDraw);
			}
			return num;
		}

		private bool AgentInventoryAllowsAbilities(PlayerAvatar player)
		{
			StatsManager instance = StatsManager.instance;
			if (!Object.op_Implicit((Object)(object)player) || !Object.op_Implicit((Object)(object)instance))
			{
				return false;
			}
			PhysGrabber physGrabber = player.physGrabber;
			PhysGrabObject val = (PhysGrabObject)((Object.op_Implicit((Object)(object)physGrabber) && physGrabber.grabbed) ? /*isinst with value type is only supported in some contexts*/: null);
			if (Object.op_Implicit((Object)(object)val) && (!((Component)val).gameObject.activeInHierarchy || val.playerGrabbing == null || !val.playerGrabbing.Contains(physGrabber)))
			{
				val = null;
			}
			ItemEquippable val2 = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent<ItemEquippable>() : null);
			ItemAttributes val3 = (Object.op_Implicit((Object)(object)val2) ? ((Component)val).GetComponent<ItemAttributes>() : null);
			string text = (Object.op_Implicit((Object)(object)val3) ? (agentInventoryInstanceName.GetValue(val3) as string) : null);
			int? heldHash = ((!string.IsNullOrEmpty(text)) ? new int?(text.GetHashCode()) : ((int?)null));
			bool heldStoredByThisPlayer = Object.op_Implicit((Object)(object)val2) && val2.IsEquipped() && (Object)(object)val2.GetOwnerPlayerAvatar() == (Object)(object)player;
			int num = AgentInventoryRules.CarriedCount(native.Id(player), instance.playerInventorySpot1, instance.playerInventorySpot2, instance.playerInventorySpot3, Object.op_Implicit((Object)(object)val2), heldHash, heldStoredByThisPlayer);
			int num2 = AgentPendingDrawCount(player, val2);
			return AgentInventoryRules.AbilitiesAllowed((num < 0) ? num : (num + num2));
		}

		private void TickAgentRadarSafely(PlayerAvatar player)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Invalid comparison between Unknown and I4
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: 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_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0300: Unknown result type (might be due to invalid IL or missing references)
			//IL_0302: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_0308: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_033a: Unknown result type (might be due to invalid IL or missing references)
			//IL_033c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0369: Unknown result type (might be due to invalid IL or missing references)
			//IL_0371: Unknown result type (might be due to invalid IL or missing references)
			//IL_0379: Unknown result type (might be due to invalid IL or missing references)
			if (agentRadarFailed)
			{
				return;
			}
			if (!Object.op_Implicit((Object)(object)GameDirector.instance) || (int)GameDirector.instance.currentState != 2)
			{
				agentRadar.Reset();
				return;
			}
			try
			{
				if (agentMapActive == null || agentMapActive.FieldType != typeof(bool))
				{
					throw new MissingFieldException("Agent radar map API changed.");
				}
				if (!Object.op_Implicit((Object)(object)player) || !Object.op_Implicit((Object)(object)player.mapToolController) || !(bool)agentMapActive.GetValue(player.mapToolController) || !agentRadar.Due(Time.timeAsDouble))
				{
					return;
				}
				FieldInfo[] array = new FieldInfo[6] { roleVoiceChat, agentSpeaking, agentEnemySpawned, agentEnemyDead, agentEnemyDying, agentEnemyHealth };
				for (int i = 0; i < array.Length; i++)
				{
					if (array[i] == null)
					{
						throw new MissingFieldException("Agent radar game API changed.");
					}
				}
				object? value = roleVoiceChat.GetValue(player);
				PlayerVoiceChat val = (PlayerVoiceChat)((value is PlayerVoiceChat) ? value : null);
				bool canSpeak = Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.ttsVoice) && !(bool)agentSpeaking.GetValue(val.ttsVoice) && !roleAnnouncements.Any((RoleAnnouncement a) => a.Id == assassinSelected);
				Vector3 val2 = (Object.op_Implicit((Object)(object)player.localCamera) ? player.localCamera.GetOverrideTransform().position : ((Component)player).transform.position);
				if (!Finite(val2))
				{
					return;
				}
				Vector3 val3 = (Object.op_Implicit((Object)(object)player.localCamera) ? ((Component)player.localCamera).transform.forward : ((Component)player).transform.forward);
				val3.y = 0f;
				if (((Vector3)(ref val3)).sqrMagnitude < 0.0001f)
				{
					val3 = ((Component)player).transform.forward;
					val3.y = 0f;
				}
				if (!Finite(val3) || ((Vector3)(ref val3)).sqrMagnitude < 0.0001f)
				{
					return;
				}
				List<AgentRadarRules.Sample> list = new List<AgentRadarRules.Sample>();
				Dictionary<int, EnemyParent> dictionary = new Dictionary<int, EnemyParent>();
				Enemy[] array2 = Object.FindObjectsOfType<Enemy>();
				foreach (Enemy val4 in array2)
				{
					if (!Object.op_Implicit((Object)(object)val4) || !((Component)val4).gameObject.activeInHierarchy)
					{
						continue;
					}
					EnemyParent componentInParent = ((Component)val4).GetComponentInParent<EnemyParent>();
					if (Object.op_Implicit((Object)(object)componentInParent) && !(bool)agentEnemySpawned.GetValue(componentInParent))
					{
						continue;
					}
					EnemyHealth component = ((Component)val4).GetComponent<EnemyHealth>();
					if (!Object.op_Implicit((Object)(object)component) || (!(bool)agentEnemyDead.GetValue(component) && !(bool)agentEnemyDying.GetValue(component) && (int)agentEnemyHealth.GetValue(component) > 0))
					{
						Vector3 val5 = (Object.op_Implicit((Object)(object)val4.CenterTransform) ? val4.CenterTransform.position : ((Component)val4).transform.position);
						Vector3 val6 = val5 - val2;
						if (Finite(val6))
						{
							float sqrMagnitude = ((Vector3)(ref val6)).sqrMagnitude;
							val6.y = 0f;
							float num = ((((Vector3)(ref val6)).sqrMagnitude < 0.0001f) ? 0f : Vector3.SignedAngle(val3, val6, Vector3.up));
							int instanceID = ((Object)val4).GetInstanceID();
							list.Add(new AgentRadarRules.Sample(instanceID, sqrMagnitude, num, AgentRadarGroup.GetKind(val4), val5.x, val5.y, val5.z));
							dictionary[instanceID] = componentInParent;
						}
					}
				}
				int? enemyId;
				string text = agentRadar.NotifyEnemies(list, Time.timeAsDouble, canSpeak, out enemyId);
				if (text != null)
				{
					EnemyParent value2 = null;
					if (enemyId.HasValue)
					{
						dictionary.TryGetValue(enemyId.Value, out value2);
					}
					AgentSpeech.Send(player, text, (text == "Enemy nearby") ? null : AgentEnemyName.Resolve(value2));
				}
			}
			catch (Exception ex)
			{
				agentRadarFailed = true;
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Agent radar stopped; role abilities retained: " + ex.GetBaseException().Message));
			}
		}

		private void InitializeAgentUpgradeSuspension()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Expected O, but got Unknown
			try
			{
				if (agentUpgradeRestarting == null || agentUpgradeRestarting.FieldType != typeof(bool))
				{
					throw new MissingFieldException("RunManager.restarting");
				}
				agentUpgradePatches = new Harmony("Guest-Role.AgentUpgradeSuspension");
				string[] array = new string[4] { "UpgradePlayerGrabStrength", "UpgradePlayerGrabRange", "UpgradePlayerThrowStrength", "UpgradePlayerSprintSpeed" };
				foreach (string text in array)
				{
					agentUpgradePatches.Patch((MethodBase)AccessTools.Method(typeof(PunManager), text, (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "AgentUpgradePurchasedPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				agentUpgradePatches.Patch((MethodBase)AccessTools.Method(typeof(RunManager), "RestartScene", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Plugin), "AgentUpgradeScenePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				agentUpgradesReady = true;
			}
			catch (Exception ex)
			{
				Harmony obj = agentUpgradePatches;
				if (obj != null)
				{
					obj.UnpatchSelf();
				}
				((BaseUnityPlugin)this).Logger.LogError((object)("Agent upgrade suspension unavailable; other roles retained: " + ex));
			}
		}

		private static Dictionary<string, int> AgentUpgradeValues(StatsManager stats, string upgrade)
		{
			return upgrade switch
			{
				"Strength" => stats.playerUpgradeStrength, 
				"Range" => stats.playerUpgradeRange, 
				"Throw" => stats.playerUpgradeThrow, 
				"Speed" => stats.playerUpgradeSpeed, 
				_ => throw new ArgumentException("Unsupported Agent suspended upgrade.", "upgrade"), 
			};
		}

		private void TickAgentUpgradeSuspension()
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Invalid comparison between Unknown and I4
			if (!agentUpgradesReady)
			{
				return;
			}
			try
			{
				bool flag = AgentUpgradeAuthority && ((Behaviour)this).enabled && hostReady && modEnabled.Value && assassinError == null && assassinSelected != null && Object.op_Implicit((Object)(object)StatsManager.instance) && Object.op_Implicit((Object)(object)PunManager.instance) && Object.op_Implicit((Object)(object)RunManager.instance) && !(bool)agentUpgradeRestarting.GetValue(RunManager.instance) && !SemiFunc.MenuLevel() && Object.op_Implicit((Object)(object)GameDirector.instance) && (int)GameDirector.instance.currentState == 2 && Object.op_Implicit((Object)(object)LevelGenerator.Instance) && LevelGenerator.Instance.Generated;