Decompiled source of Haelnak the Necromancer v1.2.1

Necromancer.dll

Decompiled 3 weeks 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.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using REPOLib.Modules;
using REPOLib.Objects.Sdk;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Animations;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.Rendering.PostProcessing;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("Autodesk.Fbx")]
[assembly: IgnoresAccessChecksTo("Discord.Sdk")]
[assembly: IgnoresAccessChecksTo("Domain_Reload")]
[assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")]
[assembly: IgnoresAccessChecksTo("FbxBuildTestAssets")]
[assembly: IgnoresAccessChecksTo("Klattersynth")]
[assembly: IgnoresAccessChecksTo("Photon3Unity3D")]
[assembly: IgnoresAccessChecksTo("PhotonChat")]
[assembly: IgnoresAccessChecksTo("PhotonRealtime")]
[assembly: IgnoresAccessChecksTo("PhotonUnityNetworking")]
[assembly: IgnoresAccessChecksTo("PhotonUnityNetworking.Utilities")]
[assembly: IgnoresAccessChecksTo("PhotonVoice.API")]
[assembly: IgnoresAccessChecksTo("PhotonVoice")]
[assembly: IgnoresAccessChecksTo("PhotonVoice.PUN")]
[assembly: IgnoresAccessChecksTo("SingularityGroup.HotReload.Runtime.Public")]
[assembly: IgnoresAccessChecksTo("Sirenix.OdinInspector.Attributes")]
[assembly: IgnoresAccessChecksTo("Sirenix.OdinInspector.Modules.Unity.Addressables")]
[assembly: IgnoresAccessChecksTo("Sirenix.OdinInspector.Modules.UnityLocalization")]
[assembly: IgnoresAccessChecksTo("Sirenix.Serialization.Config")]
[assembly: IgnoresAccessChecksTo("Sirenix.Serialization")]
[assembly: IgnoresAccessChecksTo("Sirenix.Utilities")]
[assembly: IgnoresAccessChecksTo("Unity.Addressables")]
[assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")]
[assembly: IgnoresAccessChecksTo("Unity.Burst")]
[assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")]
[assembly: IgnoresAccessChecksTo("Unity.Collections")]
[assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")]
[assembly: IgnoresAccessChecksTo("Unity.Formats.Fbx.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")]
[assembly: IgnoresAccessChecksTo("Unity.InternalAPIEngineBridge.013")]
[assembly: IgnoresAccessChecksTo("Unity.Localization")]
[assembly: IgnoresAccessChecksTo("Unity.Mathematics")]
[assembly: IgnoresAccessChecksTo("Unity.MemoryProfiler")]
[assembly: IgnoresAccessChecksTo("Unity.Postprocessing.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.ResourceManager")]
[assembly: IgnoresAccessChecksTo("Unity.ScriptableBuildPipeline")]
[assembly: IgnoresAccessChecksTo("Unity.Splines")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: IgnoresAccessChecksTo("Unity.Timeline")]
[assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Antlr3.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Core")]
[assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Flow")]
[assembly: IgnoresAccessChecksTo("Unity.VisualScripting.State")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UI")]
[assembly: IgnoresAccessChecksTo("websocket-sharp")]
[assembly: AssemblyCompany("Necromancer")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.1.0")]
[assembly: AssemblyInformationalVersion("1.2.1")]
[assembly: AssemblyProduct("Necromancer")]
[assembly: AssemblyTitle("Necromancer")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.1.0")]
[module: UnverifiableCode]
[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 VoidNecro
{
	internal enum Attack : byte
	{
		Drain,
		Bolt,
		Sweep
	}
	internal sealed class Brain : MonoBehaviour, IPunObservable
	{
		private enum Effect : byte
		{
			Appear,
			Shove,
			Loose
		}

		private float nextAttack;

		private float nextDrain;

		private float nextBolt;

		private float nextSweep;

		private float drainBlocked;

		private float drainOwed;

		private float drainHealth;

		private PlayerAvatar victim;

		private Vector3 aim;

		private bool struck;

		private bool released;

		private bool drainShook;

		private readonly HashSet<Enemy> hitEnemies = new HashSet<Enemy>();

		private Enemy enemy;

		private EnemyParent parent;

		private PhotonView view;

		private Body body;

		private Sight sight;

		private Transform feet;

		private Mode mode;

		private bool lockedOn;

		private bool looking;

		private bool wasStunned;

		private byte healthShare = byte.MaxValue;

		private PlayerAvatar target;

		private Vector3 lastSeen;

		private Vector3 lookAt;

		private Vector3 goal;

		private Vector3? noise;

		private float lastSeenAt = -99f;

		private float modeAt;

		private float chaseStarted;

		private float tipOffAt;

		private float lookAroundUntil;

		private float leaveUntil;

		private float recoverFor;

		private float nextThink;

		private float nextIdle;

		private float nextHurtLine;

		private float speed;

		private bool hasGoal;

		private bool holding;

		private Quaternion facing;

		private int spawns;

		private int boltCount;

		internal static bool debugPending;

		private Attack nextForced;

		private static readonly float[] PortalAngles = new float[9] { 50f, -50f, 90f, -90f, 25f, -25f, 0f, 130f, -130f };

		private static readonly float[] PortalSteps = new float[3] { 0f, 0.5f, -0.5f };

		private static bool debugPortal;

		private float nextFind;

		private float lookUntil;

		private readonly List<Raise> owed = new List<Raise>();

		private readonly List<Thrall> thralls = new List<Thrall>();

		private Raise raising;

		private EnemyParent reserved;

		private bool risen;

		private float riseAt;

		private float ritualEnds;

		private static Vector3? debugRitual;

		private static float BoltRelease => Clips.Event("bolt", "release", 0.55f);

		private static float SweepHit => Clips.Event("sweep", "hit", 0.45f);

		internal Enemy Enemy => enemy;

		internal Body Body => body;

		internal bool LockedOn => lockedOn;

		internal bool Alive
		{
			get
			{
				if (Object.op_Implicit((Object)(object)enemy) && Object.op_Implicit((Object)(object)enemy.Health) && !enemy.Health.dead && Object.op_Implicit((Object)(object)parent))
				{
					return parent.Spawned;
				}
				return false;
			}
		}

		private float InMode => Time.time - modeAt;

		private static float Slow => Mathf.Clamp(Plugin.DrainSlow.Value, 0.1f, 1f);

		private Vector3 RitualSpot
		{
			get
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				if (raising == null)
				{
					return ((Component)this).transform.position;
				}
				return raising.Spot;
			}
		}

		private int Keeping => thralls.Count((Thrall t) => Object.op_Implicit((Object)(object)t) && t.Alive) + owed.Count + ((raising != null && !risen) ? 1 : 0);

		private bool TryAttack(float d)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time < nextAttack || !Object.op_Implicit((Object)(object)target))
			{
				return false;
			}
			float num = Mathf.Abs(((Component)target).transform.position.y - ((Component)this).transform.position.y);
			List<Attack> list = new List<Attack>();
			if (d <= Plugin.SweepReach.Value * 0.9f && num < 1.5f && Time.time >= nextSweep)
			{
				list.Add(Attack.Sweep);
			}
			if (d >= Plugin.DrainMin.Value && d <= Plugin.DrainRange.Value && Time.time >= nextDrain && Reaches(body.Palm, target))
			{
				list.Add(Attack.Drain);
			}
			if (d >= Plugin.BoltMin.Value && d <= Plugin.BoltMax.Value && Time.time >= nextBolt && Reaches(body.StaffTip, target))
			{
				list.Add(Attack.Bolt);
			}
			if (list.Count > 0)
			{
				return Use(list[Random.Range(0, list.Count)], forced: false);
			}
			return false;
		}

		private bool Use(Attack attack, bool forced)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: 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_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)target) || target.isDisabled || target.deadSet)
			{
				return false;
			}
			Stop();
			Vector3 val = Flat(((Component)target).transform.position - ((Component)this).transform.position);
			aim = ((Vector3)(ref val)).normalized;
			if (((Vector3)(ref aim)).sqrMagnitude < 0.01f)
			{
				aim = ((Component)this).transform.forward;
			}
			facing = Quaternion.LookRotation(aim);
			struck = (released = false);
			hitEnemies.Clear();
			float num = Mathf.Max(0f, Plugin.AttackGap.Value);
			switch (attack)
			{
			case Attack.Drain:
				victim = target;
				Enter(Mode.DrainWind);
				nextDrain = Time.time + Plugin.DrainCooldown.Value;
				drainBlocked = 0f;
				SendDrain(victim, DrainPhase.WindUp, Mathf.Max(0.1f, Plugin.DrainWindUp.Value));
				Say(Line.Drain);
				break;
			case Attack.Bolt:
				Enter(Mode.Bolt);
				nextBolt = Time.time + Plugin.BoltCooldown.Value;
				Send(Cue.Bolt, BoltRelease);
				if (Random.value < 0.6f)
				{
					Say(Line.Bolt);
				}
				break;
			case Attack.Sweep:
				Enter(Mode.Sweep);
				nextSweep = Time.time + Plugin.SweepCooldown.Value;
				Send(Cue.Sweep, SweepHit);
				break;
			}
			nextAttack = Time.time + 10f;
			object[] obj = new object[4] { attack, target.playerName, null, null };
			val = Flat(((Component)target).transform.position - ((Component)this).transform.position);
			obj[2] = ((Vector3)(ref val)).magnitude;
			obj[3] = (forced ? " (forced)" : "");
			Log(string.Format("{0} at {1}, {2:0.0} m{3}", obj));
			return true;
		}

		private void Done(float recover)
		{
			nextAttack = Time.time + recover + Mathf.Max(0f, Plugin.AttackGap.Value);
			Recover(recover);
		}

		private void DrainWind()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			Stop();
			if (!DrainHolds(out var _))
			{
				EndDrain(graceful: true);
				return;
			}
			Face(((Component)victim).transform.position);
			if (!(InMode < Mathf.Max(0.1f, Plugin.DrainWindUp.Value)))
			{
				Enter(Mode.Drain);
				drainOwed = 0f;
				drainShook = false;
				drainHealth = enemy.Health.healthCurrent;
				float seconds = Mathf.Max(0.2f, Plugin.DrainSeconds.Value);
				SendDrain(victim, DrainPhase.Hold, seconds);
				Log("draining " + victim.playerName);
			}
		}

		private void Draining()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			Stop();
			if (!DrainHolds(out var why))
			{
				Log("drain broke: " + why);
				EndDrain(graceful: true);
				return;
			}
			Face(((Component)victim).transform.position);
			int healthCurrent = enemy.Health.healthCurrent;
			if (drainHealth - (float)healthCurrent >= Mathf.Max(1f, Plugin.DrainBreakHit.Value))
			{
				Log($"drain broke: hit for {drainHealth - (float)healthCurrent}");
				EndDrain(graceful: true);
				return;
			}
			drainOwed += Mathf.Max(0f, Plugin.DrainDamage.Value) * Time.deltaTime;
			bool flag = InMode >= Mathf.Max(0.2f, Plugin.DrainSeconds.Value);
			if (drainOwed >= 2f || (flag && drainOwed >= 1f))
			{
				int num = Mathf.FloorToInt(drainOwed);
				drainOwed -= num;
				Damage(victim, num);
				if (!drainShook)
				{
					drainShook = true;
					ShakeLoose(victim, body.Palm);
				}
				int num2 = Mathf.RoundToInt((float)num * Mathf.Clamp01(Plugin.DrainHeal.Value));
				if (num2 > 0 && !enemy.Health.dead)
				{
					enemy.Health.healthCurrent = Mathf.Min(enemy.Health.health, enemy.Health.healthCurrent + num2);
				}
			}
			drainHealth = enemy.Health.healthCurrent;
			if (flag)
			{
				EndDrain(graceful: true);
			}
		}

		private bool DrainHolds(out string why)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			why = null;
			if (!Object.op_Implicit((Object)(object)victim) || victim.isDisabled || victim.deadSet)
			{
				why = "victim gone";
				return false;
			}
			if (Vector3.Distance(body.Palm, Chest(victim)) > Plugin.DrainBreakRange.Value)
			{
				why = "out of range";
				return false;
			}
			drainBlocked = (Reaches(body.Palm, victim) ? 0f : (drainBlocked + Time.deltaTime));
			if (drainBlocked > Mathf.Max(0.05f, Plugin.DrainBreakBlocked.Value))
			{
				Transform blocker = sight.Blocker;
				why = (Object.op_Implicit((Object)(object)blocker) ? ("blocked by " + ((Object)blocker).name + " (layer " + LayerMask.LayerToName(((Component)blocker).gameObject.layer) + ", " + (Object.op_Implicit((Object)(object)blocker.parent) ? ((Object)blocker.parent).name : "no parent") + ")") : "blocked");
				return false;
			}
			return true;
		}

		private void EndDrain(bool graceful)
		{
			Mode mode = this.mode;
			if (mode - 8 <= Mode.Roam)
			{
				float num = Mathf.Max(0.1f, Plugin.DrainRelease.Value);
				SendDrain(victim, graceful ? DrainPhase.Release : DrainPhase.Off, num);
				victim = null;
				nextAttack = Time.time + num + Mathf.Max(0f, Plugin.AttackGap.Value);
				if (graceful)
				{
					Enter(Mode.DrainEnd);
				}
				else
				{
					Recover(0.5f);
				}
			}
		}

		private void DrainEnding()
		{
			Stop();
			if (InMode >= Mathf.Max(0.1f, Plugin.DrainRelease.Value))
			{
				Done(0.3f);
			}
		}

		private void BoltMode()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			Stop();
			float boltRelease = BoltRelease;
			if (!released && Object.op_Implicit((Object)(object)target))
			{
				Face(((Component)target).transform.position);
			}
			if (!released && InMode >= boltRelease)
			{
				released = true;
				Vector3 staffTip = body.StaffTip;
				Vector3 val = ((Object.op_Implicit((Object)(object)target) && !target.isDisabled) ? Chest(target) : (staffTip + ((Component)this).transform.forward * 5f));
				SendBolt(staffTip, val - staffTip, target);
			}
			if (InMode >= boltRelease + 0.45f)
			{
				Done(0.4f);
			}
		}

		internal void BoltHitPlayer(PlayerAvatar p, Vector3 at, Vector3 dir)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)p) && !p.isDisabled)
			{
				bool flag = (float)p.playerHealth.health <= Plugin.BoltDamage.Value;
				Damage(p, Mathf.RoundToInt(Plugin.BoltDamage.Value));
				SendHit(p, at, staff: false);
				ShakeLoose(p, at - dir);
				if (!flag)
				{
					Vector3 val = Flat(dir);
					Knock(p, ((Vector3)(ref val)).normalized * 5f + Vector3.up * 2.5f, Plugin.BoltTumble.Value);
				}
				Log("bolt hit " + p.playerName + (flag ? ": killed" : ""));
			}
		}

		internal void BoltStruck(Collider c, Vector3 at, Vector3 dir)
		{
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)c))
			{
				return;
			}
			PhysGrabObject componentInParent = ((Component)c).GetComponentInParent<PhysGrabObject>();
			if (Object.op_Implicit((Object)(object)componentInParent) && componentInParent.playerGrabbing.Count > 0 && Object.op_Implicit((Object)(object)((Component)componentInParent).GetComponent<PlayerDeathHead>()))
			{
				foreach (PhysGrabber item in componentInParent.playerGrabbing)
				{
					if (Object.op_Implicit((Object)(object)item) && Object.op_Implicit((Object)(object)item.playerAvatar) && !item.playerAvatar.isDisabled)
					{
						BoltHitPlayer(item.playerAvatar, at, dir);
						return;
					}
				}
			}
			EnemyRigidbody componentInParent2 = ((Component)c).GetComponentInParent<EnemyRigidbody>();
			Enemy val = (Object.op_Implicit((Object)(object)componentInParent2) ? componentInParent2.enemy : ((Component)c).GetComponentInParent<Enemy>());
			if (Object.op_Implicit((Object)(object)val) && (Object)(object)val != (Object)(object)enemy)
			{
				if (val.HasHealth && Plugin.BoltEnemyDamage.Value > 0f && !Serves(val))
				{
					val.Health.Hurt(Mathf.RoundToInt(Plugin.BoltEnemyDamage.Value), dir);
					Log("bolt hit a " + val.EnemyParent?.enemyName);
				}
			}
			else
			{
				Shove(at, dir, Plugin.BoltShove.Value, 0.6f);
			}
		}

		private void Sweep()
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			Stop();
			float sweepHit = SweepHit;
			if (!struck && Object.op_Implicit((Object)(object)target) && InMode < sweepHit * 0.7f)
			{
				Face(((Component)target).transform.position);
				Vector3 val = Flat(((Component)target).transform.position - ((Component)this).transform.position);
				aim = ((Vector3)(ref val)).normalized;
			}
			if (!struck && InMode >= sweepHit)
			{
				struck = true;
				Swing();
			}
			if (InMode >= sweepHit + 0.45f)
			{
				Done(0.5f);
			}
		}

		private void Swing()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: 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_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			float value = Plugin.SweepReach.Value;
			Vector3 val = ((Component)this).transform.position + Vector3.up * 1.1f;
			if (((Vector3)(ref aim)).sqrMagnitude < 0.01f)
			{
				aim = ((Component)this).transform.forward;
			}
			foreach (PlayerAvatar item in World.Targets())
			{
				Vector3 val2 = Chest(item) - ((Component)this).transform.position;
				Vector3 val3 = Flat(val2);
				if (((Vector3)(ref val3)).magnitude > value + 0.3f || val2.y < -0.6f || val2.y > 2.2f)
				{
					continue;
				}
				val3 = Flat(val2);
				if (!(Vector3.Dot(((Vector3)(ref val3)).normalized, aim) < 0.15f) && Reaches(val, item))
				{
					bool flag = (float)item.playerHealth.health <= Plugin.SweepDamage.Value;
					Damage(item, Mathf.RoundToInt(Plugin.SweepDamage.Value));
					SendHit(item, Chest(item), staff: true);
					ShakeLoose(item, ((Component)this).transform.position);
					if (!flag)
					{
						val3 = Flat(val2);
						Knock(item, ((Vector3)(ref val3)).normalized * Plugin.SweepShove.Value + Vector3.up * 2.5f, Plugin.SweepTumble.Value);
					}
					Log("swept " + item.playerName + (flag ? ": killed" : ""));
				}
			}
			Vector3 at = val + aim * value * 0.6f;
			HitEnemies(at, 0.5f + value * 0.3f, Plugin.SweepEnemyDamage.Value);
			Shove(at, aim, Plugin.SweepShove.Value * 0.5f, 0.4f + value * 0.25f);
		}

		private bool Serves(Enemy other)
		{
			Thrall component = ((Component)other).GetComponent<Thrall>();
			if (component != null)
			{
				return (Object)(object)component.Master == (Object)(object)this;
			}
			return false;
		}

		private void HitEnemies(Vector3 at, float radius, float damage)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			if (damage <= 0f)
			{
				return;
			}
			Collider[] array = Physics.OverlapSphere(at, radius, LayerMask.op_Implicit(SemiFunc.LayerMaskGetVisionObstruct()) | LayerMask.GetMask(new string[1] { "Enemy" }), (QueryTriggerInteraction)2);
			foreach (Collider val in array)
			{
				EnemyRigidbody componentInParent = ((Component)val).GetComponentInParent<EnemyRigidbody>();
				Enemy val2 = (Object.op_Implicit((Object)(object)componentInParent) ? componentInParent.enemy : ((Component)val).GetComponentInParent<Enemy>());
				if (Object.op_Implicit((Object)(object)val2) && !((Object)(object)val2 == (Object)(object)enemy) && val2.HasHealth && !Serves(val2) && hitEnemies.Add(val2))
				{
					val2.Health.Hurt(Mathf.RoundToInt(damage), aim);
					Log("hit a " + val2.EnemyParent?.enemyName);
				}
			}
		}

		private void Shove(Vector3 at, Vector3 dir, float force, float radius)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			if (force <= 0f)
			{
				return;
			}
			HashSet<PhysGrabObject> hashSet = new HashSet<PhysGrabObject>();
			Collider[] array = Physics.OverlapSphere(at, radius, LayerMask.op_Implicit(SemiFunc.LayerMaskGetPhysGrabObject()), (QueryTriggerInteraction)1);
			foreach (Collider val in array)
			{
				PhysGrabObject componentInParent = ((Component)val).GetComponentInParent<PhysGrabObject>();
				if (Object.op_Implicit((Object)(object)componentInParent) && hashSet.Add(componentInParent) && Object.op_Implicit((Object)(object)componentInParent.rb) && !componentInParent.rb.isKinematic && !Object.op_Implicit((Object)(object)((Component)componentInParent).GetComponent<EnemyRigidbody>()) && !Object.op_Implicit((Object)(object)((Component)componentInParent).GetComponent<PlayerTumble>()) && !Object.op_Implicit((Object)(object)((Component)componentInParent).GetComponent<PhysGrabHinge>()))
				{
					Rigidbody rb = componentInParent.rb;
					Vector3 val2 = ((Vector3)(ref dir)).normalized + Vector3.up * 0.3f;
					rb.AddForce(((Vector3)(ref val2)).normalized * force, (ForceMode)2);
				}
			}
			if (hashSet.Count > 0)
			{
				SendFx(Effect.Shove, at, dir);
			}
		}

		private void Awake()
		{
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Expected O, but got Unknown
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Expected O, but got Unknown
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Expected O, but got Unknown
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Expected O, but got Unknown
			enemy = ((Component)this).GetComponent<Enemy>();
			view = ((Component)this).GetComponent<PhotonView>();
			parent = ((Component)this).GetComponentInParent<EnemyParent>(true);
			Transform val = ((Component)this).transform.parent.Find("Rigidbody");
			feet = val.Find("Feet Transform");
			body = Body.Create(((Component)this).transform, val);
			body.Enemy = enemy;
			body.Brain = this;
			sight = new Sight(Object.op_Implicit((Object)(object)parent) ? ((Component)parent).transform : ((Component)this).transform.parent, () => Plugin.VisionRange.Value);
			facing = ((Component)this).transform.rotation;
			((Component)this).GetComponent<EnemyStateSpawn>().OnSpawn.AddListener(new UnityAction(OnSpawn));
			EnemyHealth component = ((Component)this).GetComponent<EnemyHealth>();
			component.onHurt.AddListener(new UnityAction(OnHurt));
			component.onDeath.AddListener(new UnityAction(OnDeath));
			EnemyStateInvestigate ears = ((Component)this).GetComponent<EnemyStateInvestigate>();
			if (ears != null)
			{
				ears.onInvestigateTriggered.AddListener((UnityAction)delegate
				{
					//IL_000c: Unknown result type (might be due to invalid IL or missing references)
					Heard(ears.onInvestigateTriggeredPosition);
				});
			}
		}

		private void OnSpawn()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			looking = (lockedOn = false);
			mode = Mode.Appear;
			body.Reset();
			if (Net.IsHost && SemiFunc.EnemySpawn(enemy))
			{
				target = null;
				noise = null;
				wasStunned = false;
				hasGoal = false;
				facing = ((Component)this).transform.rotation;
				tipOffAt = Time.time + 10f;
				nextIdle = Time.time + Random.Range(10f, 25f);
				nextAttack = Time.time + 2f;
				ResetRaising();
				Enter(Mode.Appear);
				SendFx(Effect.Appear, ((Component)this).transform.position, ((Component)this).transform.forward);
				spawns++;
				string text = (debugPending ? "by the debug key" : "naturally");
				debugPending = false;
				Log((spawns == 1) ? ("spawned " + text) : $"spawned {text} (back again, #{spawns} this level)");
			}
		}

		private void OnHurt()
		{
			body.Hurt();
			if (Net.IsHost && Time.time >= nextHurtLine && mode != Mode.Ritual)
			{
				nextHurtLine = Time.time + 1.5f;
				Say(Line.Hurt);
			}
		}

		private void OnDeath()
		{
			Safe.Run("death", body.Died);
			if (Net.IsHost)
			{
				Log("killed");
				EndDrain(graceful: false);
				AbortRaising("he died");
				CrumbleThralls("he died");
				target = null;
				parent.Despawn();
			}
		}

		private void Heard(Vector3 position)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			bool isHost = Net.IsHost;
			bool flag = isHost;
			if (flag)
			{
				Mode mode = this.mode;
				bool flag2 = ((mode - 1 <= Mode.Roam || mode == Mode.Search) ? true : false);
				flag = flag2;
			}
			if (flag)
			{
				noise = position;
			}
		}

		private void Update()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if (Net.IsHost)
			{
				if (Object.op_Implicit((Object)(object)LevelGenerator.Instance) && LevelGenerator.Instance.Generated)
				{
					Safe.Run("brain", Think);
				}
			}
			else
			{
				body.LookAt = (looking ? new Vector3?(lookAt) : ((Vector3?)null));
			}
		}

		private void Enter(Mode m)
		{
			if (mode != m)
			{
				hasGoal = (holding = false);
			}
			mode = m;
			modeAt = Time.time;
		}

		private void Think()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Invalid comparison between Unknown and I4
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0387: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03af: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0402: Unknown result type (might be due to invalid IL or missing references)
			EnemyHealth health = enemy.Health;
			healthShare = (byte)Mathf.Clamp(Mathf.RoundToInt(255f * (float)health.healthCurrent / Mathf.Max(1f, (float)health.health)), 0, 255);
			if ((int)enemy.CurrentState == 11)
			{
				EndDrain(graceful: false);
				AbortRaising("he despawned");
				CrumbleThralls("he despawned");
				target = null;
				parent.Despawn();
				return;
			}
			KeepThralls();
			if (enemy.IsStunned())
			{
				if (!wasStunned)
				{
					wasStunned = true;
					Log("stunned");
					Say(Line.Stun);
					EndDrain(graceful: false);
					if (this.mode == Mode.Ritual && !risen && Plugin.Interruptible.Value)
					{
						BreakRitual();
					}
					else if (this.mode == Mode.Behold)
					{
						Log("stunned before he could open the portal");
						DropRaise();
					}
				}
				enemy.NavMeshAgent.Disable(0.1f);
				((Component)this).transform.position = feet.position;
				looking = (lockedOn = false);
				body.LookAt = null;
				return;
			}
			Mode mode;
			if (wasStunned)
			{
				wasStunned = false;
				enemy.NavMeshAgent.Warp(feet.position, false);
				enemy.NavMeshAgent.ResetPath();
				hasGoal = false;
				nextAttack = Mathf.Min(nextAttack, Time.time + 1.5f);
				mode = this.mode;
				if (mode - 13 > Mode.Roam)
				{
					Recover(0.8f);
				}
			}
			bool flag = owed.Count > 0;
			bool flag2 = flag;
			bool flag3;
			if (flag2)
			{
				mode = this.mode;
				flag3 = ((mode == Mode.Appear || mode - 13 <= Mode.Investigate) ? true : false);
				flag2 = !flag3;
			}
			if (flag2)
			{
				StartRaise();
			}
			switch (this.mode)
			{
			case Mode.Appear:
				Stop();
				if (InMode >= Clips.Length("appear", 1.5f))
				{
					Enter(Mode.Roam);
				}
				break;
			case Mode.Spot:
				Spotting();
				break;
			case Mode.Chase:
				Chase();
				break;
			case Mode.Search:
				Search();
				break;
			case Mode.Recover:
				Recovering();
				break;
			case Mode.DrainWind:
				DrainWind();
				break;
			case Mode.Drain:
				Draining();
				break;
			case Mode.DrainEnd:
				DrainEnding();
				break;
			case Mode.Bolt:
				BoltMode();
				break;
			case Mode.Sweep:
				Sweep();
				break;
			case Mode.Approach:
				Approach();
				break;
			case Mode.Ritual:
				Ritual();
				break;
			case Mode.Behold:
				Behold();
				break;
			default:
				Hunt();
				break;
			}
			mode = this.mode;
			flag3 = ((mode - 3 <= Mode.Roam || mode - 7 <= Mode.Search) ? true : false);
			bool flag4 = flag3;
			lockedOn = flag4 && Object.op_Implicit((Object)(object)target) && !target.isDisabled;
			mode = this.mode;
			flag3 = mode - 13 <= Mode.Investigate;
			looking = flag3 || lockedOn;
			Vector3 val;
			if (this.mode == Mode.Behold && Object.op_Implicit((Object)(object)raising?.Head))
			{
				val = raising.Head.physGrabObject.centerPoint;
			}
			else
			{
				mode = this.mode;
				flag3 = mode - 13 <= Mode.Roam;
				val = (flag3 ? (RitualSpot + Vector3.up * 0.3f) : (looking ? PlayerEyes(target) : Vector3.zero));
			}
			lookAt = val;
			body.LookAt = (looking ? new Vector3?(lookAt) : ((Vector3?)null));
			Turn();
			Idle();
		}

		private void Idle()
		{
			if (!(Time.time < nextIdle))
			{
				nextIdle = Time.time + Mathf.Max(5f, Plugin.IdleSeconds.Value) * Random.Range(0.75f, 1.25f);
				Mode mode = this.mode;
				if ((mode - 1 <= Mode.Roam || mode - 5 <= Mode.Roam) ? true : false)
				{
					Say(Line.Idle);
				}
			}
		}

		private void Hunt()
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)target) && target.isDisabled)
			{
				target = null;
			}
			if (mode != Mode.Leave && (Notice() || Find()))
			{
				return;
			}
			if (mode == Mode.Leave || SemiFunc.EnemyForceLeave(enemy))
			{
				Leave();
			}
			else if (noise.HasValue)
			{
				if (mode != Mode.Investigate)
				{
					Enter(Mode.Investigate);
				}
				GoTo(noise.Value, Plugin.RoamSpeed.Value * 1.3f);
				if (Arrived(1.5f) || Stuck() || InMode > 25f)
				{
					noise = null;
					StartSearch();
				}
			}
			else
			{
				Roam();
			}
		}

		private bool Notice()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			List<PlayerAvatar> list = sight.Look(body.Eyes, ((Component)body).transform.forward);
			if (list.Count == 0)
			{
				return false;
			}
			target = list[0];
			Seen();
			chaseStarted = Time.time;
			string playerName = target.playerName;
			Vector3 val = Flat(((Component)target).transform.position - ((Component)this).transform.position);
			Log($"spotted {playerName}, {((Vector3)(ref val)).magnitude:0} m");
			Enter(Mode.Spot);
			Stop();
			if (Random.value < 0.25f)
			{
				Send(Cue.Laugh);
				Say(Line.Laugh);
			}
			else
			{
				Say(Line.Spot);
			}
			return true;
		}

		private void Spotting()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			Stop();
			if (Object.op_Implicit((Object)(object)target))
			{
				Face(((Component)target).transform.position);
			}
			if (InMode >= 1.1f)
			{
				Enter(Mode.Chase);
			}
		}

		private void StartSearch()
		{
			Enter(Mode.Search);
			lookAroundUntil = 0f;
		}

		private bool Chasing(out bool seeing, out float d)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			seeing = false;
			d = 0f;
			if (!Object.op_Implicit((Object)(object)target) || target.isDisabled || target.deadSet)
			{
				target = null;
				StartSearch();
				return false;
			}
			seeing = sight.Visible(target, body.Eyes, Plugin.VisionRange.Value * 1.5f);
			if (seeing)
			{
				Seen();
			}
			Vector3 val = Flat(((Component)target).transform.position - ((Component)this).transform.position);
			d = ((Vector3)(ref val)).magnitude;
			if (Time.time - lastSeenAt > Plugin.LoseSeconds.Value || Stuck())
			{
				Log("lost " + target.playerName);
				StartSearch();
				return false;
			}
			if (Time.time - chaseStarted > Plugin.ChaseSeconds.Value)
			{
				Log("gave up on " + target.playerName);
				target = null;
				StartSearch();
				return false;
			}
			return true;
		}

		private void Chase()
		{
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			if (FindInFight() || !Chasing(out var seeing, out var d))
			{
				return;
			}
			if (seeing && Time.time >= nextThink)
			{
				nextThink = Time.time + 0.5f;
				if (TryAttack(d))
				{
					return;
				}
			}
			float num = (holding ? 1f : 0f);
			bool flag = d > Plugin.SweepReach.Value * 0.8f && d < Mathf.Min(Plugin.DrainMin.Value, Plugin.BoltMin.Value) - 0.4f * num;
			bool flag2 = Time.time - lastSeenAt < 0.4f;
			if (flag2 && d <= Plugin.CastMax.Value + 1.5f * num && !flag)
			{
				holding = true;
				Stop();
				Face(((Component)target).transform.position);
			}
			else
			{
				holding = false;
				GoTo(flag2 ? ((Component)target).transform.position : lastSeen, Plugin.ChaseSpeed.Value);
			}
		}

		private void Recover(float seconds)
		{
			Enter(Mode.Recover);
			recoverFor = seconds;
		}

		private void Recovering()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			Stop();
			if (Object.op_Implicit((Object)(object)target))
			{
				Face(((Component)target).transform.position);
			}
			if (!(InMode < recoverFor) && !FindInFight())
			{
				if (Object.op_Implicit((Object)(object)target) && !target.isDisabled && Time.time - lastSeenAt < Plugin.LoseSeconds.Value)
				{
					Enter(Mode.Chase);
				}
				else
				{
					StartSearch();
				}
			}
		}

		private void Search()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)target) && !target.isDisabled && sight.Visible(target, body.Eyes, Plugin.VisionRange.Value))
			{
				Seen();
				Enter(Mode.Chase);
			}
			else
			{
				if (Notice() || Find())
				{
					return;
				}
				if (noise.HasValue)
				{
					target = null;
					Enter(Mode.Roam);
					return;
				}
				if (Object.op_Implicit((Object)(object)target) && !Arrived(1f) && !Stuck() && InMode < 12f)
				{
					GoTo(lastSeen, Plugin.ChaseSpeed.Value * 0.8f);
					return;
				}
				Stop();
				if (lookAroundUntil == 0f)
				{
					lookAroundUntil = Time.time + Plugin.SearchSeconds.Value;
				}
				facing *= Quaternion.Euler(0f, 45f * Time.deltaTime, 0f);
				if (Time.time > lookAroundUntil)
				{
					target = null;
					Enter(Mode.Roam);
					Log("gave up looking");
				}
			}
		}

		private void Roam()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			if (mode != Mode.Roam)
			{
				Enter(Mode.Roam);
			}
			if (SemiFunc.EnemySpawnIdlePause())
			{
				Stop();
				return;
			}
			if (hasGoal && !Arrived(1.5f) && !Stuck())
			{
				GoTo(goal, Plugin.RoamSpeed.Value);
				return;
			}
			List<LevelPoint> list = (SemiFunc.LevelPointsGetAll() ?? new List<LevelPoint>()).Where((LevelPoint p) => Object.op_Implicit((Object)(object)p) && !p.Truck).ToList();
			if (list.Count == 0)
			{
				return;
			}
			Vector3 position;
			if (Time.time >= tipOffAt)
			{
				PlayerAvatar near = Nearest();
				if (near != null)
				{
					tipOffAt = Time.time + Plugin.TipOffSeconds.Value;
					position = ((Component)(from _ in list.OrderBy(delegate(LevelPoint p)
						{
							//IL_0006: Unknown result type (might be due to invalid IL or missing references)
							//IL_0016: 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)
							//IL_0020: Unknown result type (might be due to invalid IL or missing references)
							Vector3 val = ((Component)p).transform.position - ((Component)near).transform.position;
							return ((Vector3)(ref val)).sqrMagnitude;
						}).Take(4)
						orderby Random.value
						select _).First()).transform.position;
					Log("drifting toward " + near.playerName + "'s area");
					goto IL_0161;
				}
			}
			position = ((Component)list[Random.Range(0, list.Count)]).transform.position;
			goto IL_0161;
			IL_0161:
			hasGoal = false;
			GoTo(position, Plugin.RoamSpeed.Value);
		}

		private void Leave()
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			if (mode != Mode.Leave)
			{
				LevelPoint val = SemiFunc.LevelPointGetPlayerDistance(((Component)this).transform.position, 30f, 50f, false) ?? SemiFunc.LevelPointGetFurthestFromPlayer(((Component)this).transform.position, 5f);
				if (!Object.op_Implicit((Object)(object)val))
				{
					Roam();
					return;
				}
				Enter(Mode.Leave);
				noise = null;
				leaveUntil = Time.time + 25f;
				SemiFunc.EnemyLeaveStart(enemy);
				GoTo(((Component)val).transform.position, Plugin.RoamSpeed.Value * 1.4f);
				Log("leaving");
			}
			else
			{
				GoTo(goal, Plugin.RoamSpeed.Value * 1.4f);
				if (Arrived(1.5f) || Stuck() || Time.time > leaveUntil)
				{
					Enter(Mode.Roam);
				}
			}
		}

		private void Seen()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			lastSeen = ((Component)target).transform.position;
			lastSeenAt = Time.time;
		}

		internal void Damage(PlayerAvatar p, int damage)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)p) && !p.isDisabled && !p.deadSet && damage > 0)
			{
				int num = SemiFunc.EnemyGetIndex(enemy);
				if (p.isLocal)
				{
					p.playerHealth.Hurt(damage, false, num, false);
				}
				else
				{
					p.playerHealth.HurtOther(damage, Vector3.zero, false, num, false);
				}
			}
		}

		private static void Knock(PlayerAvatar p, Vector3 force, float seconds)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)p.tumble) && !p.isDisabled && !(seconds <= 0f))
			{
				p.tumble.TumbleRequest(true, false);
				p.tumble.TumbleForce(force);
				p.tumble.TumbleTorque(-((Component)p).transform.right * 20f);
				p.tumble.TumbleOverrideTime(seconds);
			}
		}

		private bool Reaches(Vector3 from, PlayerAvatar p)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return sight.Reaches(from, p);
		}

		private bool Clear(Vector3 from, Vector3 to)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			RaycastHit[] array = Physics.RaycastAll(from, to - from, Vector3.Distance(from, to), LayerMask.GetMask(new string[1] { "Default" }), (QueryTriggerInteraction)1);
			for (int i = 0; i < array.Length; i++)
			{
				RaycastHit val = array[i];
				if (!Mine(((RaycastHit)(ref val)).transform) && !Object.op_Implicit((Object)(object)Sight.Owner(((RaycastHit)(ref val)).transform)) && !((Component)((RaycastHit)(ref val)).transform).CompareTag("Player"))
				{
					return false;
				}
			}
			return true;
		}

		private bool Mine(Transform t)
		{
			EnemyRigidbody componentInParent = ((Component)t).GetComponentInParent<EnemyRigidbody>();
			if (componentInParent != null)
			{
				return (Object)(object)componentInParent.enemy == (Object)(object)enemy;
			}
			return false;
		}

		private PlayerAvatar Nearest()
		{
			return World.Targets().OrderBy(delegate(PlayerAvatar p)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: 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)
				Vector3 val = ((Component)p).transform.position - ((Component)this).transform.position;
				return ((Vector3)(ref val)).sqrMagnitude;
			}).FirstOrDefault();
		}

		private void GoTo(Vector3 destination, float moveSpeed)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: 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)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			speed = moveSpeed;
			if (hasGoal)
			{
				Vector3 val = Flat(goal - destination);
				if (!(((Vector3)(ref val)).magnitude > 0.5f))
				{
					goto IL_0052;
				}
			}
			goal = destination;
			hasGoal = true;
			enemy.Rigidbody.notMovingTimer = 0f;
			goto IL_0052;
			IL_0052:
			enemy.NavMeshAgent.SetDestination(goal);
			enemy.NavMeshAgent.OverrideAgent(speed, enemy.NavMeshAgent.DefaultAcceleration, 0.2f);
		}

		private void Stop()
		{
			speed = 0f;
			enemy.NavMeshAgent.ResetPath();
		}

		private bool Arrived(float within)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (hasGoal)
			{
				Vector3 val = Flat(((Component)this).transform.position - goal);
				return ((Vector3)(ref val)).magnitude < within + 0.5f;
			}
			return false;
		}

		private bool Stuck()
		{
			if (hasGoal && speed > 0.5f)
			{
				return enemy.Rigidbody.notMovingTimer > 3f;
			}
			return false;
		}

		private void Face(Vector3 point)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Flat(point - ((Component)this).transform.position);
			if (((Vector3)(ref val)).sqrMagnitude > 0.01f)
			{
				facing = Quaternion.LookRotation(val);
			}
		}

		private void Turn()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Flat(enemy.NavMeshAgent.AgentVelocity);
			bool flag;
			switch (mode)
			{
			case Mode.Appear:
			case Mode.Spot:
			case Mode.Recover:
			case Mode.DrainWind:
			case Mode.Drain:
			case Mode.DrainEnd:
			case Mode.Bolt:
			case Mode.Sweep:
			case Mode.Ritual:
			case Mode.Behold:
				flag = true;
				break;
			default:
				flag = false;
				break;
			}
			if (!flag && (mode != Mode.Search || !(speed <= 0f)) && ((Vector3)(ref val)).sqrMagnitude > 0.04f)
			{
				facing = Quaternion.LookRotation(val);
			}
			else if (mode == Mode.Chase && Object.op_Implicit((Object)(object)target))
			{
				Face(((Component)target).transform.position);
			}
			((Component)this).transform.rotation = Quaternion.RotateTowards(((Component)this).transform.rotation, facing, ((mode == Mode.Drain) ? 120f : 200f) * Time.deltaTime);
		}

		private void Say(Line line)
		{
			int num = Body.Pick(line);
			if (num >= 0)
			{
				if (SemiFunc.IsMultiplayer())
				{
					view.RPC("SayRPC", (RpcTarget)0, new object[2]
					{
						(byte)line,
						(byte)num
					});
				}
				else
				{
					body.Say(line, num);
				}
			}
		}

		private void Send(Cue cue, float value = 0f)
		{
			if (SemiFunc.IsMultiplayer())
			{
				view.RPC("CueRPC", (RpcTarget)0, new object[2]
				{
					(byte)cue,
					value
				});
			}
			else
			{
				body.Play(cue, value);
			}
		}

		private void SendDrain(PlayerAvatar p, DrainPhase phase, float seconds)
		{
			if (SemiFunc.IsMultiplayer())
			{
				view.RPC("DrainRPC", (RpcTarget)0, new object[4]
				{
					Object.op_Implicit((Object)(object)p) ? p.photonView.ViewID : (-1),
					(byte)phase,
					seconds,
					Slow
				});
			}
			else
			{
				PlayDrain(p, phase, seconds, Slow);
			}
		}

		private void PlayDrain(PlayerAvatar p, DrainPhase phase, float seconds, float slow)
		{
			switch (phase)
			{
			case DrainPhase.WindUp:
				body.Play(Cue.DrainStart, seconds);
				break;
			case DrainPhase.Hold:
				body.Play(Cue.DrainHold, seconds);
				break;
			case DrainPhase.Release:
				body.Play(Cue.DrainEnd, seconds);
				break;
			}
			body.Drain.Set(p, phase, seconds, slow);
		}

		private void SendHit(PlayerAvatar p, Vector3 point, bool staff)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.IsMultiplayer())
			{
				view.RPC("HitRPC", (RpcTarget)0, new object[3]
				{
					Object.op_Implicit((Object)(object)p) ? p.photonView.ViewID : (-1),
					point,
					staff
				});
			}
			else
			{
				body.Hit(point, p, staff);
			}
		}

		private void SendBolt(Vector3 origin, Vector3 dir, PlayerAvatar p)
		{
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			int num = (Object.op_Implicit((Object)(object)view) ? view.ViewID : 0) * 1000 + ++boltCount % 1000;
			float num2 = Mathf.Max(1f, Plugin.BoltSpeed.Value);
			float num3 = Mathf.Max(0f, Plugin.BoltTurn.Value);
			if (SemiFunc.IsMultiplayer())
			{
				view.RPC("BoltRPC", (RpcTarget)0, new object[6]
				{
					num,
					origin,
					dir,
					Object.op_Implicit((Object)(object)p) ? p.photonView.ViewID : (-1),
					num2,
					num3
				});
			}
			else
			{
				Bolt.Fire(this, ((Component)this).transform.parent, num, origin, dir, p, num2, num3);
			}
		}

		internal void SendBurst(int id, Vector3 at, Vector3 normal)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.IsMultiplayer())
			{
				view.RPC("BurstRPC", (RpcTarget)0, new object[3] { id, at, normal });
			}
			else
			{
				Bolt.Burst(id, at, normal);
			}
		}

		private void SendFx(Effect kind, Vector3 at, Vector3 dir)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.IsMultiplayer())
			{
				view.RPC("FxRPC", (RpcTarget)0, new object[3]
				{
					(byte)kind,
					at,
					dir
				});
			}
			else
			{
				PlayFx(kind, at, dir);
			}
		}

		private void PlayFx(Effect kind, Vector3 at, Vector3 dir)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			switch (kind)
			{
			case Effect.Appear:
				body.Appear(at);
				break;
			case Effect.Shove:
				Fx.Burst(at, dir, 25, 3f, Fx.Void, Fx.VoidDeep, 0.2f);
				Fx.Shake(at, 3f, 8f, 0.3f);
				break;
			case Effect.Loose:
				Fx.Flash(at, 0.6f, 1.5f, 0.3f, Fx.Fel);
				Fx.Burst(at, dir, 18, 2f, Fx.Fel, Color.Lerp(Fx.Fel, Color.white, 0.5f), 0.2f, 0.05f, 0.6f);
				Sfx.At(at, "fx_drain_end", Plugin.AttackVolume.Value * 0.7f, 14f, 1.4f);
				break;
			}
		}

		[PunRPC]
		private void CueRPC(byte cue, float value, PhotonMessageInfo info = default(PhotonMessageInfo))
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.MasterOnlyRPC(info))
			{
				body.Play((Cue)cue, value);
			}
		}

		[PunRPC]
		private void SayRPC(byte line, byte index, PhotonMessageInfo info = default(PhotonMessageInfo))
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.MasterOnlyRPC(info))
			{
				body.Say((Line)line, index);
			}
		}

		[PunRPC]
		private void DrainRPC(int player, byte phase, float seconds, float slow, PhotonMessageInfo info = default(PhotonMessageInfo))
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.MasterOnlyRPC(info))
			{
				PlayDrain((player >= 0) ? SemiFunc.PlayerAvatarGetFromPhotonID(player) : null, (DrainPhase)phase, seconds, slow);
			}
		}

		[PunRPC]
		private void HitRPC(int player, Vector3 point, bool staff, PhotonMessageInfo info = default(PhotonMessageInfo))
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.MasterOnlyRPC(info))
			{
				body.Hit(point, (player >= 0) ? SemiFunc.PlayerAvatarGetFromPhotonID(player) : null, staff);
			}
		}

		[PunRPC]
		private void BoltRPC(int id, Vector3 origin, Vector3 dir, int player, float boltSpeed, float turn, PhotonMessageInfo info = default(PhotonMessageInfo))
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.MasterOnlyRPC(info))
			{
				Bolt.Fire(this, ((Component)this).transform.parent, id, origin, dir, (player >= 0) ? SemiFunc.PlayerAvatarGetFromPhotonID(player) : null, boltSpeed, turn);
			}
		}

		[PunRPC]
		private void BurstRPC(int id, Vector3 at, Vector3 normal, PhotonMessageInfo info = default(PhotonMessageInfo))
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.MasterOnlyRPC(info))
			{
				Bolt.Burst(id, at, normal);
			}
		}

		[PunRPC]
		private void FxRPC(byte kind, Vector3 at, Vector3 dir, PhotonMessageInfo info = default(PhotonMessageInfo))
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.MasterOnlyRPC(info))
			{
				PlayFx((Effect)kind, at, dir);
			}
		}

		[PunRPC]
		private void RiteRPC(Vector3 spot, float seconds, byte line, PhotonMessageInfo info = default(PhotonMessageInfo))
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.MasterOnlyRPC(info))
			{
				body.Ritual(spot, seconds, (line == byte.MaxValue) ? (-1) : line);
			}
		}

		[PunRPC]
		private void RiteBreakRPC(PhotonMessageInfo info = default(PhotonMessageInfo))
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.MasterOnlyRPC(info))
			{
				body.RiteBroken();
			}
		}

		[PunRPC]
		private void RaiseRPC(int thrallView, int player, int colour, Vector3 spot, PhotonMessageInfo info = default(PhotonMessageInfo))
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.MasterOnlyRPC(info))
			{
				PhotonView val = PhotonView.Find(thrallView);
				Thrall thrall = ((val != null) ? ((Component)val).GetComponentInChildren<Thrall>(true) : null);
				PlayerAvatar player2 = ((player >= 0) ? SemiFunc.PlayerAvatarGetFromPhotonID(player) : null);
				if (Object.op_Implicit((Object)(object)thrall))
				{
					thrall.Raised(player2, colour, spot);
				}
				else
				{
					Plugin.Log.LogWarning((object)$"raise: no thrall with view {thrallView} here");
				}
			}
		}

		public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			if (stream.IsWriting)
			{
				stream.SendNext((object)(byte)mode);
				stream.SendNext((object)looking);
				stream.SendNext((object)lookAt);
				stream.SendNext((object)lockedOn);
				stream.SendNext((object)healthShare);
			}
			else if (SemiFunc.MasterOnlyRPC(info))
			{
				mode = (Mode)(byte)stream.ReceiveNext();
				looking = (bool)stream.ReceiveNext();
				lookAt = (Vector3)stream.ReceiveNext();
				lockedOn = (bool)stream.ReceiveNext();
				healthShare = (byte)stream.ReceiveNext();
			}
		}

		internal static void DebugSpawn(Vector3 spot, Quaternion facing)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			EnemyParent val = Shell.All().FirstOrDefault();
			debugPending = !Object.op_Implicit((Object)(object)val) || !val.Spawned;
			if (!Object.op_Implicit((Object)(object)val))
			{
				ManualLogSource log = Plugin.Log;
				List<EnemyParent> list = Enemies.SpawnEnemy(Shell.Setup, spot, facing, false);
				log.LogInfo((object)((list != null && list.Count > 0) ? $"debug: spawned at {spot}" : "debug: spawn failed"));
				return;
			}
			if (!val.Spawned)
			{
				val.Spawn();
			}
			val.Enemy.EnemyTeleported(spot);
			Plugin.Log.LogInfo((object)$"debug: moved to {spot}");
		}

		internal static void DebugDespawn()
		{
			foreach (EnemyParent item in from p in Shell.All()
				where p.Spawned
				select p)
			{
				Brain componentInChildren = ((Component)item).GetComponentInChildren<Brain>();
				if (Object.op_Implicit((Object)(object)componentInChildren))
				{
					componentInChildren.EndDrain(graceful: false);
					componentInChildren.AbortRaising("the debug key");
					componentInChildren.CrumbleThralls("the debug key");
				}
				item.Despawn();
				Plugin.Log.LogInfo((object)"debug: despawned");
			}
		}

		internal static void DebugStun()
		{
			foreach (Brain item in Shell.Living())
			{
				if (item.enemy.HasStateStunned)
				{
					item.enemy.StateStunned.Set(4f);
					Plugin.Log.LogInfo((object)"debug: stunned");
				}
			}
		}

		internal static void DebugKill()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			foreach (Brain item in Shell.Living())
			{
				if (item.enemy.HasHealth)
				{
					item.enemy.Health.Hurt(item.enemy.Health.healthCurrent + 1, Vector3.up);
					Plugin.Log.LogInfo((object)"debug: killed");
				}
			}
		}

		internal static void DebugAttack(Attack? which)
		{
			foreach (Brain item in Shell.Living())
			{
				bool flag = item.enemy.IsStunned();
				bool flag2 = flag;
				if (!flag2)
				{
					Mode mode = item.mode;
					bool flag3 = ((mode == Mode.Appear || mode - 8 <= Mode.Recover) ? true : false);
					flag2 = flag3;
				}
				if (flag2)
				{
					Plugin.Log.LogInfo((object)$"debug: busy ({item.mode})");
					continue;
				}
				item.target = item.Nearest();
				if (Object.op_Implicit((Object)(object)item.target))
				{
					item.Seen();
					item.chaseStarted = Time.time;
					Attack attack = which ?? item.nextForced;
					if (!which.HasValue)
					{
						item.nextForced = (Attack)((int)(attack + 1) % 3);
					}
					bool flag4 = item.Use(attack, forced: true);
					Plugin.Log.LogInfo((object)string.Format("debug: {0} on {1}{2}", attack, item.target.playerName, flag4 ? "" : " (couldn't)"));
				}
			}
		}

		private void Log(string text)
		{
			Plugin.Debug($"necromancer #{body.Id}: {text}");
		}

		internal static Vector3 Flat(Vector3 v)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(v.x, 0f, v.z);
		}

		internal static Vector3 Chest(PlayerAvatar player)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if (player.isTumbling && Object.op_Implicit((Object)(object)player.tumble))
			{
				return ((Component)player.tumble).transform.position;
			}
			return ((Component)player).transform.position + Vector3.up * (player.isCrawling ? 0.3f : (player.isCrouching ? 0.6f : 1f));
		}

		internal static Vector3 PlayerEyes(PlayerAvatar player)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)player.PlayerVisionTarget) && Object.op_Implicit((Object)(object)player.PlayerVisionTarget.VisionTransform))
			{
				return player.PlayerVisionTarget.VisionTransform.position;
			}
			return ((Component)player).transform.position + Vector3.up * 1.5f;
		}

		private bool FindInFight()
		{
			if (Time.time < lookUntil)
			{
				return Find();
			}
			return false;
		}

		private bool Find()
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.FindHeads.Value || Time.time < nextFind || raising != null || owed.Count > 0 || !Object.op_Implicit((Object)(object)Shell.ThrallSetup))
			{
				return false;
			}
			nextFind = Time.time + 0.5f;
			if (Keeping >= Mathf.Max(0, Plugin.MaxThralls.Value))
			{
				return false;
			}
			List<PlayerAvatar> list = SemiFunc.PlayerGetList();
			if (list == null)
			{
				return false;
			}
			Vector3 eyes = body.Eyes;
			PlayerAvatar who = null;
			PlayerDeathHead val = null;
			float num = Mathf.Max(1f, Plugin.FindRange.Value);
			foreach (PlayerAvatar item in list)
			{
				if (Heads.Free(item, out var h))
				{
					Vector3 centerPoint = h.physGrabObject.centerPoint;
					float num2 = Vector3.Distance(eyes, centerPoint);
					if (!(num2 > num) && Clear(eyes, centerPoint) && !Taken(item))
					{
						num = num2;
						who = item;
						val = h;
					}
				}
			}
			if (Object.op_Implicit((Object)(object)val))
			{
				return StartPortal(who, val, val.physGrabObject.centerPoint, debug: false);
			}
			return false;
		}

		internal void ShakeLoose(PlayerAvatar p, Vector3 from)
		{
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.KnockLoose.Value || !Object.op_Implicit((Object)(object)p) || !Object.op_Implicit((Object)(object)p.physGrabber))
			{
				return;
			}
			PhysGrabber physGrabber = p.physGrabber;
			List<PlayerAvatar> list = SemiFunc.PlayerGetList();
			if (list == null)
			{
				return;
			}
			foreach (PlayerAvatar item in list)
			{
				PlayerDeathHead val = (Object.op_Implicit((Object)(object)item) ? item.playerDeathHead : null);
				if (Object.op_Implicit((Object)(object)val) && val.triggered && Object.op_Implicit((Object)(object)val.physGrabObject) && val.physGrabObject.playerGrabbing.Contains(physGrabber))
				{
					if (SemiFunc.IsMultiplayer())
					{
						physGrabber.photonView.RPC("ReleaseObjectRPC", (RpcTarget)0, new object[3]
						{
							false,
							1f,
							val.photonView.ViewID
						});
					}
					else
					{
						physGrabber.ReleaseObject(val.photonView.ViewID, 1f);
					}
					Heads.Loosed(val, physGrabber);
					nextFind = 0f;
					lookUntil = Time.time + 6f;
					Vector3 val2 = Flat(val.physGrabObject.centerPoint - from);
					Vector3 normalized;
					if (!(((Vector3)(ref val2)).sqrMagnitude > 0.01f))
					{
						Vector3 val3 = Flat(((Component)p).transform.forward);
						normalized = ((Vector3)(ref val3)).normalized;
					}
					else
					{
						normalized = ((Vector3)(ref val2)).normalized;
					}
					val2 = normalized + Vector3.up * 0.6f;
					World.Jolt(val, physGrabber, val2 * 3f);
					SendFx(Effect.Loose, val.physGrabObject.centerPoint, val2);
					Log("knocked " + item.playerName + "'s head out of " + p.playerName + "'s hands");
				}
			}
		}

		private static bool Taken(PlayerAvatar p)
		{
			foreach (Brain item in Shell.Living())
			{
				if ((Object)(object)item.raising?.Player == (Object)(object)p || item.owed.Exists((Raise r) => (Object)(object)r.Player == (Object)(object)p))
				{
					return true;
				}
			}
			return false;
		}

		private bool StartPortal(PlayerAvatar who, PlayerDeathHead head, Vector3 toward, bool debug)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			if (!PlacePortal(toward, out var floor, out var val))
			{
				Log("no clear space beside him for a portal" + (Object.op_Implicit((Object)(object)who) ? (" for " + who.playerName) : ""));
				Heads.Cool(head, 10f);
				return false;
			}
			reserved = Thrall.Reserve(this, floor);
			if (!Object.op_Implicit((Object)(object)reserved))
			{
				return false;
			}
			raising = new Raise
			{
				Player = who,
				Spot = floor,
				Colour = ColourOf(who),
				Debug = debug,
				Portal = true,
				Head = head,
				Facing = val
			};
			risen = false;
			EndDrain(graceful: false);
			Stop();
			Send(Cue.Idle);
			Enter(Mode.Behold);
			Face(toward);
			float value = Random.value;
			if (value < 0.35f)
			{
				Send(Cue.Laugh);
				Say(Line.Laugh);
			}
			else if (value < 0.7f)
			{
				Say(Line.Gloat);
			}
			object[] obj = new object[5]
			{
				Object.op_Implicit((Object)(object)who) ? who.playerName : "a",
				null,
				null,
				null,
				null
			};
			Vector3 val2 = Flat(toward - ((Component)this).transform.position);
			obj[1] = ((Vector3)(ref val2)).magnitude;
			obj[2] = (debug ? " (debug)" : "");
			obj[3] = floor;
			obj[4] = val;
			Log(string.Format("found {0}'s head {1:0.0} m off{2}; portal at {3}, facing {4}", obj));
			return true;
		}

		private void Behold()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			Stop();
			if (raising == null)
			{
				Enter(Mode.Roam);
				return;
			}
			if (Object.op_Implicit((Object)(object)raising.Head))
			{
				Face(raising.Head.physGrabObject.centerPoint);
			}
			if (!raising.Debug && !Heads.Free(raising.Player, out var _))
			{
				Log("the head was taken before he began");
				DropRaise();
			}
			else if (InMode >= 0.9f)
			{
				BeginRitual();
			}
		}

		private bool PlacePortal(Vector3 toward, out Vector3 floor, out Vector3 facing)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)this).transform.position;
			Vector3 val = Flat(toward - position);
			Vector3 stop;
			Vector3 normalized;
			if (!(((Vector3)(ref val)).sqrMagnitude > 0.01f))
			{
				stop = Flat(((Component)this).transform.forward);
				normalized = ((Vector3)(ref stop)).normalized;
			}
			else
			{
				normalized = ((Vector3)(ref val)).normalized;
			}
			val = normalized;
			float num = Mathf.Max(1f, Plugin.PortalDistance.Value);
			float[] portalSteps = PortalSteps;
			foreach (float num2 in portalSteps)
			{
				float[] portalAngles = PortalAngles;
				foreach (float num3 in portalAngles)
				{
					Vector3 position2 = position + Quaternion.Euler(0f, num3, 0f) * val * (num + num2);
					if (Nav.Sample(position2, 0.6f, out var onMesh) && !(Mathf.Abs(onMesh.y - position.y) > 1f) && Room(onMesh, 0.45f) && Clear(body.Eyes, onMesh + Vector3.up * 0.4f) && Nav.Straight(position, onMesh, out stop))
					{
						Vector3 val2 = Flat(toward - onMesh);
						floor = onMesh;
						Vector3 normalized2;
						if (!(((Vector3)(ref val2)).sqrMagnitude > 0.25f))
						{
							stop = Flat(onMesh - position);
							normalized2 = ((Vector3)(ref stop)).normalized;
						}
						else
						{
							normalized2 = ((Vector3)(ref val2)).normalized;
						}
						facing = normalized2;
						return true;
					}
				}
			}
			stop = (floor = (facing = Vector3.zero));
			return false;
		}

		private static bool Room(Vector3 floor, float radius)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			int mask = LayerMask.GetMask(new string[2] { "Default", "PhysGrabObjectHinge" });
			return !Physics.CheckCapsule(floor + Vector3.up * (0.2f + radius), floor + Vector3.up * (2.1f - radius), radius, mask, (QueryTriggerInteraction)1);
		}

		private void DebugPortalNow()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			PlayerAvatar instance = PlayerAvatar.instance;
			if (Object.op_Implicit((Object)(object)instance))
			{
				if (Keeping >= Mathf.Max(1, Plugin.MaxThralls.Value))
				{
					Plugin.Log.LogInfo((object)$"debug: he already keeps {Keeping} thralls (MaxThralls)");
				}
				else
				{
					Plugin.Log.LogInfo((object)(StartPortal(instance, null, ((Component)instance).transform.position, debug: true) ? "debug: portal" : "debug: no room for a portal here"));
				}
			}
		}

		internal static void DebugPortal(Vector3 spawnAt, Vector3 near)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			debugPortal = true;
			if (!Shell.Living().Any())
			{
				Vector3 val = Flat(near - spawnAt);
				DebugSpawn(spawnAt, Quaternion.LookRotation((((Vector3)(ref val)).sqrMagnitude > 0.01f) ? val : Vector3.forward));
			}
		}

		internal static void PlayerDied(PlayerAvatar p, int enemyIndex)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			Enemy val = SemiFunc.EnemyGetFromIndex(enemyIndex);
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)p))
			{
				return;
			}
			Brain brain = ((Component)val).GetComponent<Brain>();
			bool byThrall = false;
			if (!Object.op_Implicit((Object)(object)brain))
			{
				Thrall component = ((Component)val).GetComponent<Thrall>();
				if (component != null)
				{
					if (!Plugin.ThrallKillsRaise.Value)
					{
						Plugin.Debug(p.playerName + " was killed by a thrall; ThrallKillsRaise is off");
						return;
					}
					brain = component.Master;
					byThrall = true;
				}
			}
			if (Object.op_Implicit((Object)(object)brain) && brain.Alive)
			{
				brain.Killed(p, DeathSpot(p), byThrall);
			}
		}

		private static Vector3 DeathSpot(PlayerAvatar p)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ((p.isTumbling && Object.op_Implicit((Object)(object)p.tumble)) ? ((Component)p.tumble).transform.position : ((Component)p).transform.position);
			val = Rite.Floor(val + Vector3.up * 0.2f);
			if (!Nav.Sample(val, 2f, out var onMesh))
			{
				return val;
			}
			return onMesh;
		}

		private static int ColourOf(PlayerAvatar p)
		{
			int[] array = ((Object.op_Implicit((Object)(object)p) && Object.op_Implicit((Object)(object)p.playerAvatarVisuals) && Object.op_Implicit((Object)(object)p.playerAvatarVisuals.playerCosmetics)) ? p.playerAvatarVisuals.playerCosmetics.colorsEquipped : null);
			int num = 7;
			if (array == null || num >= array.Length || array[num] < 0)
			{
				return 0;
			}
			return array[num];
		}

		private void Killed(PlayerAvatar p, Vector3 where, bool byThrall)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			Log(string.Format("killed {0}{1} at {2}", p.playerName, byThrall ? " (through a thrall)" : "", where));
			if (mode != Mode.Ritual)
			{
				Say(Line.Gloat);
			}
			if (Keeping >= Mathf.Max(0, Plugin.MaxThralls.Value))
			{
				Log($"already keeps {Keeping} thralls; {p.playerName} stays dead");
				return;
			}
			if (Thrall.HasThrall(p))
			{
				Log(p.playerName + " already walks as a thrall");
				return;
			}
			Owe(new Raise
			{
				Player = p,
				Spot = where,
				Colour = ColourOf(p)
			});
		}

		private void Owe(Raise r)
		{
			owed.Add(r);
		}

		private void StartRaise()
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			raising = owed[0];
			owed.RemoveAt(0);
			if (!raising.Debug && (!Object.op_Implicit((Object)(object)raising.Player) || !raising.Player.deadSet))
			{
				Log("the body's gone (revived, or they left)");
				raising = null;
				return;
			}
			if (!Object.op_Implicit((Object)(object)Shell.ThrallSetup))
			{
				raising = null;
				return;
			}
			EndDrain(graceful: false);
			Send(Cue.Idle);
			reserved = Thrall.Reserve(this, raising.Spot);
			if (!Object.op_Implicit((Object)(object)reserved))
			{
				Log("no thrall could be made");
				raising = null;
				return;
			}
			risen = false;
			if (CanCast())
			{
				BeginRitual();
				return;
			}
			Enter(Mode.Approach);
			Log("gliding to " + (Object.op_Implicit((Object)(object)raising.Player) ? raising.Player.playerName : "the") + "'s body");
		}

		private bool CanCast()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = raising.Spot + Vector3.up * 0.4f;
			Vector3 val2 = Flat(val - ((Component)this).transform.position);
			float magnitude = ((Vector3)(ref val2)).magnitude;
			if (!(magnitude <= Mathf.Max(0.5f, Plugin.ApproachDistance.Value)))
			{
				if (magnitude <= Plugin.CastDistance.Value)
				{
					return Clear(body.Eyes, val);
				}
				return false;
			}
			return true;
		}

		private void Approach()
		{
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			if (raising == null)
			{
				Enter(Mode.Roam);
				return;
			}
			if (!raising.Debug && (!Object.op_Implicit((Object)(object)raising.Player) || !raising.Player.deadSet))
			{
				Log("the body was revived (or its player left) before he reached it");
				DropRaise();
				return;
			}
			if (CanCast())
			{
				if (!(InMode > 0.3f))
				{
					Vector3 val = Flat(raising.Spot - ((Component)this).transform.position);
					if (!(((Vector3)(ref val)).magnitude <= Plugin.ApproachDistance.Value))
					{
						goto IL_00a3;
					}
				}
				BeginRitual();
				return;
			}
			goto IL_00a3;
			IL_00a3:
			GoTo(raising.Spot, Plugin.ChaseSpeed.Value);
			if (InMode > Mathf.Max(3f, Plugin.RaiseGiveUp.Value) || Stuck())
			{
				Log("couldn't reach the body");
				DropRaise();
			}
		}

		private void BeginRitual()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			Stop();
			Enter(Mode.Ritual);
			Face(RitualSpot);
			risen = false;
			float num = Mathf.Max(1f, Plugin.RitualSeconds.Value);
			float num2 = Clips.Length("ritual", 3.5f);
			float num3 = Mathf.Clamp(num2 / num, 0.5f, 2f);
			riseAt = Clips.Event("ritual", "rise", num2 * 0.83f) / num3;
			ritualEnds = Mathf.Max(num2 / num3, riseAt + 0.6f);
			nextAttack = Time.time + ritualEnds + Mathf.Max(0f, Plugin.AttackGap.Value);
			int num4 = Body.PickFitting(Line.Rise, riseAt - 0.2f);
			if (SemiFunc.IsMultiplayer())
			{
				view.RPC("RiteRPC", (RpcTarget)0, new object[3]
				{
					raising.Spot,
					num,
					(byte)((num4 < 0) ? 255u : ((uint)num4))
				});
			}
			else
			{
				body.Ritual(raising.Spot, num, num4);
			}
			Log(string.Format("{0} for {1}, rising in {2:0.0} s", raising.Portal ? "portal" : "ritual", Object.op_Implicit((Object)(object)raising.Player) ? raising.Player.playerName : "nobody", riseAt));
		}

		private void Ritual()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			Stop();
			if (raising == null)
			{
				Recover(0.5f);
				return;
			}
			Face(RitualSpot);
			if (!risen && !raising.Debug && (!Object.op_Implicit((Object)(object)raising.Player) || !raising.Player.deadSet))
			{
				Log("the body was revived (or its player left) before it rose");
				BreakRitual();
				return;
			}
			if (!risen && raising.Portal && !raising.Debug && !Heads.Free(raising.Player, out var _))
			{
				Log("the head was taken (held, saved or claimed) before the body came through");
				Heads.Cool(raising.Head);
				BreakRitual();
				return;
			}
			if (!risen && InMode >= riseAt)
			{
				if (Thrall.Ready(reserved))
				{
					RiseNow();
				}
				else if (InMode > riseAt + 3f)
				{
					Log("the thrall never got ready");
					BreakRitual();
					return;
				}
			}
			if (risen && InMode >= ritualEnds)
			{
				raising = null;
				reserved = null;
				nextAttack = Mathf.Min(nextAttack, Time.time + 1.5f);
				if (Random.value < 0.35f)
				{
					Send(Cue.Laugh);
					Say(Line.Laugh);
					Recover(Clips.Length("laugh", 2f));
				}
				else
				{
					Recover(0.5f);
				}
			}
		}

		private void RiseNow()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			risen = true;
			Thrall compone