SukunaMod.dll

Decompiled 17 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("SukunaMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.0.6.0")]
[assembly: AssemblyInformationalVersion("0.0.6+b1b14cecae8d139e15a604312507429f73f5cb7f")]
[assembly: AssemblyProduct("SukunaMod")]
[assembly: AssemblyTitle("SukunaMod")]
[assembly: AssemblyVersion("0.0.6.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SukunaMod
{
	internal static class Patches
	{
		[HarmonyPatch(typeof(InitializeGame), "Start")]
		[HarmonyPrefix]
		private static void SkipColdOpens(InitializeGame __instance)
		{
			if (Plugin.Instance.SkipColdOpens.Value)
			{
				if (__instance.playColdOpenCinematic || __instance.playColdOpenCinematic2)
				{
					Plugin.Log.LogInfo((object)"Skipping the cold-open cinematic.");
				}
				__instance.playColdOpenCinematic = false;
				__instance.playColdOpenCinematic2 = false;
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "ActivateItem_performed")]
		[HarmonyPrefix]
		private static bool BlockItemUse(PlayerControllerB __instance, CallbackContext context)
		{
			if (((NetworkBehaviour)__instance).IsOwner)
			{
				return !SukunaFuga.BlocksItemUse;
			}
			return true;
		}

		[HarmonyPatch(typeof(PlayerControllerB), "ActivateItem_canceled")]
		[HarmonyPrefix]
		private static bool BlockItemRelease(PlayerControllerB __instance, CallbackContext context)
		{
			if (((NetworkBehaviour)__instance).IsOwner)
			{
				return !SukunaFuga.BlocksItemUse;
			}
			return true;
		}
	}
	[BepInPlugin("arnon.sukunamod", "Sukuna Mod", "0.0.6")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "arnon.sukunamod";

		public const string Name = "Sukuna Mod";

		public const string Version = "0.0.6";

		internal static Plugin Instance;

		internal static ManualLogSource Log;

		internal ConfigEntry<Key> DismantleKey;

		internal ConfigEntry<Key> CleaveKey;

		internal ConfigEntry<Key> HyperSpeedKey;

		internal ConfigEntry<Key> FugaKey;

		internal ConfigEntry<Key> RctKey;

		internal ConfigEntry<int> DismantleDamage;

		internal ConfigEntry<float> DismantleRange;

		internal ConfigEntry<float> DismantleCooldown;

		internal ConfigEntry<int> DismantleCharges;

		internal ConfigEntry<float> DismantleMinInterval;

		internal ConfigEntry<float> DismantleStunSeconds;

		internal ConfigEntry<float> StunImmunitySeconds;

		internal ConfigEntry<float> MarkSeconds;

		internal ConfigEntry<int> CleaveMarkBonus;

		internal ConfigEntry<bool> ShowEnemyHealthBars;

		internal ConfigEntry<int> CleaveDamage;

		internal ConfigEntry<float> CleaveRadius;

		internal ConfigEntry<float> CleaveReach;

		internal ConfigEntry<float> CleaveCooldown;

		internal ConfigEntry<float> CleaveKnockback;

		internal ConfigEntry<float> FugaChargeSeconds;

		internal ConfigEntry<float> FugaCooldown;

		internal ConfigEntry<int> FugaMinDamage;

		internal ConfigEntry<int> FugaMaxDamage;

		internal ConfigEntry<float> FugaMaxRadius;

		internal ConfigEntry<float> FugaKnockback;

		internal ConfigEntry<float> FugaStunSeconds;

		internal ConfigEntry<float> FugaGlowSeconds;

		internal ConfigEntry<float> FugaSpeedOfSound;

		internal ConfigEntry<float> FugaMaxArrowSpeed;

		internal ConfigEntry<float> FugaKettleTopPitch;

		internal ConfigEntry<float> FugaRoarSeconds;

		internal ConfigEntry<float> FugaRumbleSeconds;

		internal ConfigEntry<float> FugaRumbleRange;

		internal ConfigEntry<float> FugaSmokeStart;

		internal ConfigEntry<float> FugaSmokeEnd;

		internal ConfigEntry<float> FugaGroundFireSeconds;

		internal ConfigEntry<float> FugaSoundDipSeconds;

		internal ConfigEntry<bool> FugaScreenEffects;

		internal ConfigEntry<float> FugaScorchSeconds;

		internal ConfigEntry<float> FugaShakeSeconds;

		internal ConfigEntry<float> FugaFovKick;

		internal ConfigEntry<float> FugaHitstop;

		internal ConfigEntry<float> FugaFlickerFrom;

		internal ConfigEntry<float> FugaLightBrightness;

		internal ConfigEntry<int> FugaMaxLights;

		internal ConfigEntry<float> RctHealPerSecond;

		internal ConfigEntry<float> RctRange;

		internal ConfigEntry<bool> ShowCooldowns;

		internal ConfigEntry<float> ScarSeconds;

		internal ConfigEntry<float> SlashLength;

		internal ConfigEntry<float> SlashVolume;

		internal ConfigEntry<float> FugaVolume;

		internal ConfigEntry<float> HyperSpeed;

		internal ConfigEntry<float> AfterHyperSeconds;

		internal ConfigEntry<int> CoilHeadHP;

		internal ConfigEntry<int> JesterHP;

		internal ConfigEntry<int> DefaultUnkillableHP;

		internal ConfigEntry<bool> HitPlayers;

		internal ConfigEntry<bool> PowersEnabled;

		internal ConfigEntry<bool> SkipColdOpens;

		internal ConfigEntry<Key> ToggleKey1;

		internal ConfigEntry<Key> ToggleKey2;

		internal ConfigEntry<Key> ToggleKey3;

		internal ConfigEntry<float> ToggleHoldSeconds;

		private static StreamWriter trace;

		private static readonly object traceLock = new object();

		internal static volatile string Section = "starting";

		internal static volatile string Scene = "";

		internal static int Frames;

		private static Thread watchdog;

		internal static void Trace(string message)
		{
			try
			{
				if (trace == null)
				{
					trace = new StreamWriter(Path.Combine(Paths.BepInExRootPath, "SukunaMod-trace.log"), append: false)
					{
						AutoFlush = true
					};
				}
				lock (traceLock)
				{
					trace.WriteLine($"{DateTime.Now:HH:mm:ss.fff} {message}");
				}
			}
			catch
			{
			}
		}

		private static void StartWatchdog()
		{
			watchdog = new Thread((ThreadStart)delegate
			{
				int num = -1;
				int num2 = 0;
				while (true)
				{
					Thread.Sleep(1000);
					int num3 = Volatile.Read(in Frames);
					if (num3 == num)
					{
						num2++;
						if (num2 == 5 || num2 % 30 == 0)
						{
							Trace($"WATCHDOG: no new frame for {num2}s, in [{Section}], scene [{Scene}]");
						}
					}
					else
					{
						if (num2 >= 5)
						{
							Trace($"WATCHDOG: frames resumed after {num2}s");
						}
						num2 = 0;
					}
					num = num3;
				}
			})
			{
				IsBackground = true,
				Name = "SukunaMod watchdog"
			};
			watchdog.Start();
		}

		private void Awake()
		{
			//IL_093c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0941: Unknown result type (might be due to invalid IL or missing references)
			//IL_0947: Expected O, but got Unknown
			//IL_0947: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			DismantleKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Keys", "Dismantle", (Key)40, "Fire a long-range slash that cuts through everything in a line.");
			CleaveKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Keys", "Cleave", (Key)38, "Heavy close-range cut that hits everything around your crosshair.");
			HyperSpeedKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Keys", "HyperSpeed", (Key)53, "Hold to move at hyper speed. Steer with WASD and your camera.");
			DismantleDamage = ((BaseUnityPlugin)this).Config.Bind<int>("Dismantle", "Damage", 2, "Hit force per target (a shovel hit is 1).");
			DismantleRange = ((BaseUnityPlugin)this).Config.Bind<float>("Dismantle", "MaxRange", 60f, "How far the slash travels before it fades, in meters. Walls still stop it.");
			DismantleCharges = ((BaseUnityPlugin)this).Config.Bind<int>("Dismantle", "Charges", 3, "Slashes you can fire back to back before waiting.");
			DismantleCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Dismantle", "RechargeSeconds", 1.5f, "Seconds to recharge one slash (charges come back one at a time).");
			DismantleMinInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Dismantle", "MinInterval", 0.2f, "Shortest time between two slashes, in seconds.");
			DismantleStunSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Dismantle", "StaggerSeconds", 0.8f, "How long a Dismantle hit stuns an enemy (0 = off).");
			StunImmunitySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Dismantle", "StaggerImmunitySeconds", 3f, "After a stagger, the same enemy can't be staggered again for this long.");
			MarkSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Dismantle", "MarkSeconds", 5f, "How long a Dismantle hit leaves its cut mark on an enemy. Another hit refreshes it.");
			CleaveDamage = ((BaseUnityPlugin)this).Config.Bind<int>("Cleave", "Damage", 5, "Hit force per target (a shovel hit is 1).");
			CleaveRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Cleave", "Radius", 2.5f, "Half the width of the area Cleave cuts, in meters.");
			CleaveReach = ((BaseUnityPlugin)this).Config.Bind<float>("Cleave", "Reach", 9f, "How far in front of you Cleave cuts, in meters. Everything between you and that distance is hit.");
			CleaveCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Cleave", "Cooldown", 3f, "Seconds between cleaves.");
			CleaveMarkBonus = ((BaseUnityPlugin)this).Config.Bind<int>("Cleave", "MarkBonusDamage", 5, "Extra damage when Cleave hits an enemy carrying a Dismantle cut mark (the mark is used up).");
			CleaveKnockback = ((BaseUnityPlugin)this).Config.Bind<float>("Cleave", "Knockback", 25f, "How hard Cleave throws enemies back (starting speed in meters per second, 0 = off).");
			ShowCooldowns = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "ShowCooldowns", true, "Show ability cooldowns on the right side of the screen while the powers are on.");
			FugaKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Keys", "Fuga", (Key)17, "Hold to charge Fuga, let go to keep the charge, left click to fire, press again to cancel.");
			RctKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Keys", "ReverseCursedTechnique", (Key)36, "Hold to heal: the player you are looking at, or yourself if you aren't looking at anyone.");
			FugaChargeSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Fuga", "ChargeSeconds", 2.5f, "Seconds of holding to reach full charge.");
			FugaCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Fuga", "Cooldown", 6f, "Seconds after firing before you can charge again.");
			FugaMinDamage = ((BaseUnityPlugin)this).Config.Bind<int>("Fuga", "MinDamage", 3, "Hit force at the lowest charge (a shovel hit is 1).");
			FugaMaxDamage = ((BaseUnityPlugin)this).Config.Bind<int>("Fuga", "MaxDamage", 20, "Hit force at full charge.");
			FugaMaxRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Fuga", "MaxRadius", 14f, "Blast radius at full charge, in meters (about 3 m at the lowest charge).");
			FugaKnockback = ((BaseUnityPlugin)this).Config.Bind<float>("Fuga", "Knockback", 35f, "How hard the blast throws enemies at full charge (0 = off).");
			FugaStunSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Fuga", "WideStunSeconds", 1f, "Stun for enemies outside the blast but within 2.5x its radius, at full charge (half at the lowest). 0 = off.");
			FugaGlowSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Fuga", "GlowSeconds", 4f, "How long the warm glow after the blast takes to fade, in seconds.");
			FugaLightBrightness = ((BaseUnityPlugin)this).Config.Bind<float>("Fuga", "LightBrightness", 1f, "Brightness multiplier for the light Fuga leaves behind.");
			FugaMaxLights = ((BaseUnityPlugin)this).Config.Bind<int>("Fuga", "MaxLights", 12, "Most Fuga glow lights at once; the oldest go out first.");
			FugaMaxArrowSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Fuga", "MaxArrowSpeed", 250f, "Arrow speed at full charge, in meters per second (60 at the lowest).");
			FugaKettleTopPitch = ((BaseUnityPlugin)this).Config.Bind<float>("Fuga", "KettleTopPitch", 2.6f, "Pitch of the kettle whistle at full charge (1.3 = the old top, 2.6 = an octave above it).");
			FugaSpeedOfSound = ((BaseUnityPlugin)this).Config.Bind<float>("Fuga", "SpeedOfSound", 150f, "How fast the shockwave and boom travel, in meters per second. Lower = a longer gap between the flash and the boom (capped at 2 s).");
			FugaShakeSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Fuga", "ShakeSeconds", 5f, "Longest screen shake at full charge, in seconds.");
			FugaFovKick = ((BaseUnityPlugin)this).Config.Bind<float>("Fuga", "FovKick", 12f, "Field-of-view kick when the shockwave hits you, in degrees.");
			FugaHitstop = ((BaseUnityPlugin)this).Config.Bind<float>("Fuga", "Hitstop", 0.1f, "Freeze-frame for the shooter at full charge, in seconds (0 = off).");
			FugaFlickerFrom = ((BaseUnityPlugin)this).Config.Bind<float>("Fuga", "FlickerFromCharge", 0.6f, "Charge (0 to 1) from which a blast flickers the lights across the map.");
			FugaScreenEffects = ((BaseUnityPlugin)this).Config.Bind<bool>("Fuga", "ScreenEffects", true, "Brief bloom, exposure and colour-fringe punch at detonation, and dimming while it gathers.");
			FugaSmokeStart = ((BaseUnityPlugin)this).Config.Bind<float>("Fuga", "SmokeStart", 3.5f, "Seconds after the blast when smoke starts rising from the cooling edges.");
			FugaSmokeEnd = ((BaseUnityPlugin)this).Config.Bind<float>("Fuga", "SmokeEnd", 8f, "Seconds after the blast by which the smoke has thinned away.");
			FugaGroundFireSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Fuga", "GroundFireSeconds", 5f, "How long the ground keeps burning at full charge (3 s at the lowest).");
			FugaScorchSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Fuga", "ScorchSeconds", 20f, "How long the scorch mark under the blast lasts (0 = off).");
			RctHealPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("ReverseCursedTechnique", "HealPerSecond", 25f, "Health restored per second while held (players have 100).");
			RctRange = ((BaseUnityPlugin)this).Config.Bind<float>("ReverseCursedTechnique", "Range", 15f, "How far away a friend can be healed, in meters.");
			ShowEnemyHealthBars = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "ShowEnemyHealthBars", true, "Show a small health bar over enemies for a few seconds after a modded player hurts them.");
			SlashLength = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "SlashLength", 2f, "How long the Dismantle and Cleave cuts are drawn (1 = the old length). Only the look; the hit range doesn't change.");
			ScarSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "ScarSeconds", 10f, "How long the molten slash scars on walls and floors last.");
			SlashVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Sound", "SlashVolume", 1f, "Volume of the slash sounds, 0 to 1.");
			FugaVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Sound", "FugaVolume", 0.6f, "Volume of all Fuga sounds, 0 to 1.");
			FugaRoarSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Sound", "FugaRoarSeconds", 7f, "How long the fireball's roar lasts at full charge.");
			FugaRumbleSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Sound", "FugaRumbleSeconds", 9f, "How long the deep sub rumble lasts.");
			FugaRumbleRange = ((BaseUnityPlugin)this).Config.Bind<float>("Sound", "FugaRumbleRange", 400f, "How far away a full-charge Fuga can be heard, in meters.");
			FugaSoundDipSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Sound", "FugaSoundDipSeconds", 1.5f, "How long the game's other sounds dip after a close blast (0 = off).");
			HyperSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "HyperSpeed", 35f, "Movement speed while hyper speed is held, in meters per second.");
			AfterHyperSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "AfterHyperSeconds", 10f, "Seconds of no fall damage after you let go of hyper speed (you also take none while holding it).");
			CoilHeadHP = ((BaseUnityPlugin)this).Config.Bind<int>("UnkillableHP", "CoilHead", 6, "Damage a Coil-head takes before it is destroyed (Dismantle does 2, Cleave 5).");
			JesterHP = ((BaseUnityPlugin)this).Config.Bind<int>("UnkillableHP", "Jester", 12, "Damage a Jester takes before it is destroyed.");
			DefaultUnkillableHP = ((BaseUnityPlugin)this).Config.Bind<int>("UnkillableHP", "Default", 10, "Damage any other normally unkillable enemy (Ghost girl, Hygrodere, Old Bird, Earth Leviathan, bees...) takes before it is destroyed.");
			HitPlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "HitPlayers", false, "Let your slashes damage other players.");
			PowersEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "PowersEnabled", false, "Whether the powers are on. Toggle it in game by holding the three toggle keys; the choice is remembered.");
			SkipColdOpens = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SkipColdOpens", true, "Skip the occasional cold-open cinematics when the game starts.");
			ToggleKey1 = ((BaseUnityPlugin)this).Config.Bind<Key>("Toggle", "Key1", (Key)33, "Hold this and the other two toggle keys together to turn the powers on or off.");
			ToggleKey2 = ((BaseUnityPlugin)this).Config.Bind<Key>("Toggle", "Key2", (Key)35, "Second toggle key.");
			ToggleKey3 = ((BaseUnityPlugin)this).Config.Bind<Key>("Toggle", "Key3", (Key)25, "Third toggle key.");
			ToggleHoldSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Toggle", "HoldSeconds", 1f, "How long to hold the toggle keys.");
			Harmony.CreateAndPatchAll(typeof(Patches), "arnon.sukunamod");
			GameObject val = new GameObject("SukunaMod");
			Object.DontDestroyOnLoad((Object)val);
			((Object)val).hideFlags = (HideFlags)61;
			val.AddComponent<SukunaController>();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Sukuna Mod 0.0.6 loaded. The King of Curses is awake.");
			Trace("Sukuna Mod 0.0.6 loaded");
			StartWatchdog();
			SceneManager.sceneLoaded += delegate(Scene scene, LoadSceneMode mode)
			{
				Scene = ((Scene)(ref scene)).name;
				Trace("scene loaded: " + ((Scene)(ref scene)).name);
			};
		}
	}
	public static class SukunaAudio
	{
		private const int Rate = 44100;

		private static AudioClip dismantle;

		private static AudioClip cleave;

		private static AudioClip boom;

		private static AudioClip launch;

		private static AudioClip gather;

		private static AudioClip crack;

		private static AudioClip deepBoom;

		internal static AudioClip KettleRush;

		internal static AudioClip KettleWhistle;

		public static void Init()
		{
			dismantle = MakeClip("SukunaDismantle", Dismantle());
			cleave = MakeClip("SukunaCleave", Cleave());
			boom = MakeClip("SukunaFugaBoom", Boom());
			launch = MakeClip("SukunaFugaLaunch", Launch());
			gather = MakeClip("SukunaFugaGather", GatherClip());
			crack = MakeClip("SukunaFugaCrack", CrackClip());
			deepBoom = MakeClip("SukunaFugaDeepBoom", DeepBoomClip());
			KettleRush = MakeClip("SukunaKettleRush", Loop(RushClip(), 0.2f));
			KettleWhistle = MakeClip("SukunaKettleWhistle", Loop(WhistleClip(), 0.2f));
		}

		internal static float WhistlePitch(float charge)
		{
			float num = Mathf.Clamp(Plugin.Instance.FugaKettleTopPitch.Value, 1.3f, 3f);
			return Mathf.Lerp(0.72f, 1.3f, charge) + (num - 1.3f) * Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(0.6f, 1f, charge));
		}

		public static void Play(SlashKind kind, Vector3 position)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			AudioClip clip = ((kind == SlashKind.Dismantle) ? dismantle : cleave);
			float volume = Mathf.Clamp01(Plugin.Instance.SlashVolume.Value) * ((kind == SlashKind.Dismantle) ? 0.55f : 0.7f);
			PlayAt(clip, position, volume, 3f, 40f);
		}

		public static void PlayBoom(Vector3 position, float charge)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			float volume = Mathf.Clamp01(Plugin.Instance.FugaVolume.Value) * Mathf.Lerp(0.45f, 1f, charge);
			PlayAt(boom, position, volume, 10f, 150f);
		}

		public static void PlayLaunch(Vector3 position, float charge)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			float volume = Mathf.Clamp01(Plugin.Instance.FugaVolume.Value) * Mathf.Lerp(0.35f, 0.6f, charge);
			PlayAt(launch, position, volume, 3f, 40f);
		}

		public static void PlayBlast(Vector3 point, float charge, float distance, float audibleRange, bool lineOfSight)
		{
			//IL_0062: 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_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: 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_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Clamp01(Plugin.Instance.FugaVolume.Value);
			if (num <= 0f)
			{
				return;
			}
			float num2 = Mathf.Clamp01(distance / Mathf.Max(1f, audibleRange));
			float pitch = Mathf.Lerp(1.15f, 0.78f, charge);
			float num3 = Mathf.Clamp01((charge - 0.4f) / 0.6f);
			if (distance < 45f)
			{
				PlayAt(crack, point, num * Mathf.Lerp(0.35f, 0.7f, charge) * (1f - distance / 45f), 4f, 45f);
			}
			if (distance < 60f)
			{
				SetPitch(PlayAt(boom, point, num * Mathf.Lerp(0.45f, 1f, charge), 10f, 60f), pitch);
				if (num3 > 0f)
				{
					PlayAt(deepBoom, point, num * num3, 15f, 80f);
				}
				return;
			}
			Vector3 val = (((Object)(object)StartOfRound.Instance != (Object)null && (Object)(object)StartOfRound.Instance.activeCamera != (Object)null) ? ((Component)StartOfRound.Instance.activeCamera).transform.position : point);
			Vector3 val2 = point - val;
			Vector3 normalized = ((Vector3)(ref val2)).normalized;
			float cutoff = Mathf.Lerp(3000f, 250f, num2) * (lineOfSight ? 1f : 0.5f);
			Distant(PlayAt(boom, val + normalized * 4f, num * Mathf.Lerp(0.4f, 1f, charge) * Mathf.Lerp(1f, 0.3f, num2), 1f, 500f), cutoff, pitch);
			if (num3 > 0f)
			{
				Distant(PlayAt(deepBoom, val + normalized * 4f, num * num3 * Mathf.Lerp(1f, 0.45f, num2), 1f, 500f), cutoff, 1f);
			}
		}

		private static void SetPitch(AudioSource source, float pitch)
		{
			if ((Object)(object)source != (Object)null)
			{
				source.pitch = pitch;
			}
		}

		private static void Distant(AudioSource source, float cutoff, float pitch)
		{
			if (!((Object)(object)source == (Object)null))
			{
				source.spatialBlend = 0.5f;
				source.pitch = pitch;
				((Component)source).gameObject.AddComponent<AudioLowPassFilter>().cutoffFrequency = cutoff;
			}
		}

		public static void PlayGather(Vector3 position, float charge, float seconds)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			float volume = Mathf.Clamp01(Plugin.Instance.FugaVolume.Value) * Mathf.Lerp(0.3f, 0.55f, charge);
			AudioSource val = PlayAt(gather, position, volume, 5f, 80f);
			if ((Object)(object)val != (Object)null && (Object)(object)gather != (Object)null)
			{
				val.pitch = Mathf.Clamp(gather.length / Mathf.Max(0.1f, seconds), 0.5f, 3f);
			}
		}

		private static AudioSource PlayAt(AudioClip clip, Vector3 position, float volume, float minDistance, float maxDistance)
		{
			//IL_0018: 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_0023: 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_00ca: Expected O, but got Unknown
			if ((Object)(object)clip == (Object)null || volume <= 0f)
			{
				return null;
			}
			GameObject val = new GameObject("SukunaSound");
			val.transform.position = position;
			AudioSource val2 = val.AddComponent<AudioSource>();
			val2.clip = clip;
			val2.spatialBlend = 1f;
			val2.rolloffMode = (AudioRolloffMode)1;
			val2.minDistance = minDistance;
			val2.maxDistance = maxDistance;
			val2.dopplerLevel = 0f;
			val2.volume = volume;
			PlayerControllerB val3 = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
			if ((Object)(object)val3 != (Object)null && (Object)(object)val3.movementAudio != (Object)null)
			{
				val2.outputAudioMixerGroup = val3.movementAudio.outputAudioMixerGroup;
			}
			val2.Play();
			Object.Destroy((Object)val, clip.length * 2f + 0.1f);
			return val2;
		}

		internal static AudioSource Loop(AudioClip clip, Transform parent, float maxDistance)
		{
			//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)
			if ((Object)(object)clip == (Object)null || (Object)(object)parent == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject("SukunaLoop");
			val.transform.SetParent(parent, false);
			AudioSource val2 = val.AddComponent<AudioSource>();
			val2.clip = clip;
			val2.loop = true;
			val2.spatialBlend = 1f;
			val2.rolloffMode = (AudioRolloffMode)1;
			val2.minDistance = 2f;
			val2.maxDistance = maxDistance;
			val2.dopplerLevel = 0f;
			val2.volume = 0f;
			PlayerControllerB val3 = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
			if ((Object)(object)val3 != (Object)null && (Object)(object)val3.movementAudio != (Object)null)
			{
				val2.outputAudioMixerGroup = val3.movementAudio.outputAudioMixerGroup;
			}
			val2.Play();
			return val2;
		}

		private static float[] Loop(float[] data, float fadeSeconds)
		{
			int num = Mathf.Min((int)(fadeSeconds * 44100f), data.Length / 3);
			int num2 = data.Length - num;
			float[] array = new float[num2];
			for (int i = 0; i < num2; i++)
			{
				array[i] = data[i];
			}
			for (int j = 0; j < num; j++)
			{
				float num3 = (float)j / (float)num;
				array[j] = data[j] * num3 + data[num2 + j] * (1f - num3);
			}
			return array;
		}

		private static float[] RushClip()
		{
			Random random = new Random(8);
			float[] array = new float[97020];
			float num = 0f;
			float num2 = 0f;
			float num3 = 0f;
			float num4 = 0f;
			for (int i = 0; i < array.Length; i++)
			{
				float num5 = (float)(random.NextDouble() * 2.0 - 1.0);
				num += Coefficient(1400f) * (num5 - num);
				num2 += Coefficient(250f) * (num - num2);
				if (random.NextDouble() < 0.00040816326530612246)
				{
					num4 = 1f;
				}
				num4 *= 0.9985f;
				num3 += Coefficient(500f) * (num5 - num3);
				array[i] = (num - num2) * 0.7f + num3 * num4 * 1.5f;
			}
			return array;
		}

		private static float[] WhistleClip()
		{
			Random random = new Random(9);
			float[] array = new float[97020];
			float num = 0f;
			float num2 = 0f;
			float num3 = 0f;
			float num4 = 0f;
			float num5 = 0f;
			for (int i = 0; i < array.Length; i++)
			{
				float num6 = (float)i / 44100f;
				float num7 = 1f + 0.004f * Mathf.Sin(MathF.PI * 11f * num6);
				num += MathF.PI * 3700f * num7 / 44100f;
				num2 += MathF.PI * 3746f * num7 / 44100f;
				num3 += MathF.PI * 7400f * num7 / 44100f;
				float num8 = (float)(random.NextDouble() * 2.0 - 1.0);
				num4 += Coefficient(2600f) * (num8 - num4);
				num5 += Coefficient(1300f) * (num4 - num5);
				array[i] = Mathf.Sin(num) * 0.5f + Mathf.Sin(num2) * 0.35f + Mathf.Sin(num3) * 0.08f + (num4 - num5) * 0.5f;
			}
			return array;
		}

		private static float[] DeepBoomClip()
		{
			Random random = new Random(10);
			float[] array = new float[264600];
			float num = 0f;
			float num2 = 0f;
			float num3 = 0f;
			for (int i = 0; i < array.Length; i++)
			{
				float t = (float)i / 44100f;
				float num4 = (float)(random.NextDouble() * 2.0 - 1.0);
				num += Coefficient(90f) * (num4 - num);
				num2 += Coefficient(60f) * (num - num2);
				num3 += MathF.PI * 2f * (22f + 25f * Decay(t, 0.6f)) / 44100f;
				float num5 = Mathf.Sin(num3) * Attack(t, 0.03f) * Decay(t, 2f);
				float num6 = num2 * 14f * Attack(t, 0.15f) * Decay(t, 2.4f);
				array[i] = (float)Math.Tanh(1.4f * (num5 + num6));
			}
			return array;
		}

		private static AudioClip MakeClip(string name, float[] data)
		{
			float num = 0f;
			foreach (float num2 in data)
			{
				num = Mathf.Max(num, Mathf.Abs(num2));
			}
			if (num > 0f)
			{
				for (int j = 0; j < data.Length; j++)
				{
					data[j] *= 0.8f / num;
				}
			}
			AudioClip obj = AudioClip.Create(name, data.Length, 1, 44100, false);
			obj.SetData(data, 0);
			return obj;
		}

		private static float Coefficient(float cutoffHz)
		{
			return 1f - Mathf.Exp(MathF.PI * -2f * cutoffHz / 44100f);
		}

		private static float Attack(float t, float time)
		{
			return 1f - Mathf.Exp((0f - t) / time);
		}

		private static float Decay(float t, float time)
		{
			if (!(t < 0f))
			{
				return Mathf.Exp((0f - t) / time);
			}
			return 0f;
		}

		private static float[] Dismantle()
		{
			Random random = new Random(1);
			float[] array = new float[17640];
			float num = 0f;
			float num2 = 0f;
			for (int i = 0; i < array.Length; i++)
			{
				float num3 = (float)i / 44100f;
				float cutoffHz = Mathf.Lerp(2500f, 9000f, Mathf.Clamp01(num3 / 0.1f));
				float num4 = (float)(random.NextDouble() * 2.0 - 1.0);
				num += Coefficient(cutoffHz) * (num4 - num);
				num2 += Coefficient(1800f) * (num - num2);
				float num5 = (num - num2) * Attack(num3, 0.002f) * Decay(num3, 0.05f);
				float num6 = Mathf.Sin(MathF.PI * 6600f * num3) * Decay(num3, 0.1f) * 0.12f + Mathf.Sin(MathF.PI * 9900f * num3) * Decay(num3, 0.06f) * 0.07f;
				array[i] = num5 + num6 * Attack(num3, 0.001f);
			}
			return array;
		}

		private static float[] Boom()
		{
			Random random = new Random(3);
			float[] array = new float[132300];
			float num = 0f;
			float num2 = 0f;
			float num3 = 0f;
			float num4 = 0f;
			for (int i = 0; i < array.Length; i++)
			{
				float t = (float)i / 44100f;
				float num5 = (float)(random.NextDouble() * 2.0 - 1.0);
				num += Coefficient(220f) * (num5 - num);
				num2 += Coefficient(120f) * (num - num2);
				num3 += Coefficient(900f) * (num5 - num3);
				num4 += MathF.PI * 2f * (28f + 50f * Decay(t, 0.25f)) / 44100f;
				float num6 = Mathf.Sin(num4) * Attack(t, 0.012f) * Decay(t, 0.9f);
				float num7 = num2 * 6f * Attack(t, 0.03f) * Decay(t, 1.1f);
				float num8 = num3 * Attack(t, 0.004f) * Decay(t, 0.12f) * 0.6f;
				array[i] = (float)Math.Tanh(1.2f * (num6 + num7 + num8));
			}
			return array;
		}

		private static float[] CrackClip()
		{
			Random random = new Random(6);
			float[] array = new float[15435];
			float num = 0f;
			float num2 = 0f;
			for (int i = 0; i < array.Length; i++)
			{
				float t = (float)i / 44100f;
				float num3 = (float)(random.NextDouble() * 2.0 - 1.0);
				num += Coefficient(6000f) * (num3 - num);
				num2 += Coefficient(700f) * (num - num2);
				array[i] = (float)Math.Tanh(2f * (num - num2) * Attack(t, 0.001f) * Decay(t, 0.05f));
			}
			return array;
		}

		private static float[] GatherClip()
		{
			Random random = new Random(5);
			float[] array = new float[26460];
			float num = 0f;
			float num2 = 0f;
			float num3 = 0f;
			for (int i = 0; i < array.Length; i++)
			{
				float num4 = (float)i / 44100f / 0.6f;
				float num5 = (float)(random.NextDouble() * 2.0 - 1.0);
				num += Coefficient(Mathf.Lerp(300f, 3000f, num4 * num4)) * (num5 - num);
				num2 += Coefficient(150f) * (num - num2);
				num3 += MathF.PI * 2f * Mathf.Lerp(60f, 220f, num4 * num4) / 44100f;
				float num6 = num4 * num4 * (1f - Mathf.Clamp01((num4 - 0.96f) / 0.04f));
				array[i] = ((num - num2) * 0.8f + Mathf.Sin(num3) * 0.35f) * num6;
			}
			return array;
		}

		private static float[] Launch()
		{
			Random random = new Random(4);
			float[] array = new float[30870];
			float num = 0f;
			float num2 = 0f;
			for (int i = 0; i < array.Length; i++)
			{
				float num3 = (float)i / 44100f;
				float num4 = (float)(random.NextDouble() * 2.0 - 1.0);
				num += Coefficient(Mathf.Lerp(600f, 2500f, Mathf.Clamp01(num3 / 0.25f))) * (num4 - num);
				num2 += Coefficient(250f) * (num - num2);
				array[i] = (num - num2) * Attack(num3, 0.04f) * Decay(num3, 0.18f);
			}
			return array;
		}

		private static float[] Cleave()
		{
			Random random = new Random(2);
			float[] array = new float[33075];
			float num = 0f;
			float num2 = 0f;
			float num3 = 0f;
			for (int i = 0; i < array.Length; i++)
			{
				float num4 = (float)i / 44100f;
				float num5 = (float)(random.NextDouble() * 2.0 - 1.0);
				num += Coefficient(4500f) * (num5 - num);
				num2 += Coefficient(500f) * (num - num2);
				float num6 = 0f;
				float[] array2 = new float[2] { 0f, 0.1f };
				foreach (float num7 in array2)
				{
					float num8 = num4 - num7;
					if (num8 >= 0f)
					{
						num6 += Attack(num8, 0.003f) * Decay(num8, 0.07f);
					}
				}
				float num9 = num4 - 0.02f;
				num3 += MathF.PI * 2f * (45f + 70f * Decay(num9, 0.05f)) / 44100f;
				float num10 = ((num9 >= 0f) ? (Mathf.Sin(num3) * Attack(num9, 0.004f) * Decay(num9, 0.2f)) : 0f);
				array[i] = (float)Math.Tanh(1.4f * ((num - num2) * num6 + 0.6f * num10));
			}
			return array;
		}
	}
	public class FugaArrival : MonoBehaviour
	{
		private float delay;

		private float distance;

		private float charge;

		private float radius;

		private float audibleRange;

		private bool lineOfSight;

		private Vector3 point;

		private bool shooterIsLocal;

		private bool indoors;

		private float age;

		public static void Schedule(Vector3 point, Vector3 normal, float charge, float radius, bool indoors, bool shooterIsLocal)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: 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_0014: 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_006b: 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_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ListenerPosition();
			if (val == Vector3.zero)
			{
				return;
			}
			float num = Vector3.Distance(val, point);
			float num2 = Mathf.Lerp(90f, Mathf.Max(100f, Plugin.Instance.FugaRumbleRange.Value), charge);
			if (!(num > num2) || !(num > radius * 4f))
			{
				int num3 = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.collidersAndRoomMaskAndDefault : (-1));
				Vector3 val2 = point + ((Vector3)(ref normal)).normalized * 1.5f;
				bool flag = !Physics.Linecast(val, val2, num3, (QueryTriggerInteraction)1);
				float num4 = Mathf.Lerp(40f, 250f, charge);
				if ((flag && num < num4) || num < radius * 1.5f)
				{
					float num5 = 1f - Mathf.Clamp01(num / num4) * 0.7f;
					SukunaHud.DoubleFlash(Mathf.Lerp(0.25f, 0.85f, Mathf.Pow(charge, 1.5f)) * num5);
					PostFx.Punch(Mathf.Lerp(0.3f, 1f, charge) * num5);
				}
				FugaArrival fugaArrival = new GameObject("SukunaFugaArrival").AddComponent<FugaArrival>();
				fugaArrival.delay = Mathf.Min(num / Mathf.Max(20f, Plugin.Instance.FugaSpeedOfSound.Value), 2f);
				fugaArrival.indoors = indoors;
				fugaArrival.distance = num;
				fugaArrival.charge = charge;
				fugaArrival.radius = radius;
				fugaArrival.audibleRange = num2;
				fugaArrival.lineOfSight = flag;
				fugaArrival.point = point;
				fugaArrival.shooterIsLocal = shooterIsLocal;
				Plugin.Trace($"fuga felt: distance={num:0} sight={flag} delay={fugaArrival.delay:0.00}");
			}
		}

		private static Vector3 ListenerPosition()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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)
			if ((Object)(object)StartOfRound.Instance != (Object)null && (Object)(object)StartOfRound.Instance.activeCamera != (Object)null)
			{
				return ((Component)StartOfRound.Instance.activeCamera).transform.position;
			}
			PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
			if (!((Object)(object)val != (Object)null) || !((Object)(object)val.gameplayCamera != (Object)null))
			{
				return Vector3.zero;
			}
			return ((Component)val.gameplayCamera).transform.position;
		}

		private void Update()
		{
			age += Time.deltaTime;
			if (!(age < delay))
			{
				Arrive();
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}

		private void Arrive()
		{
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			float num = radius * 1.5f;
			float num2 = ((distance <= num) ? 1f : (1f - Mathf.Clamp01((distance - num) / Mathf.Max(1f, audibleRange - num))));
			float num3 = Mathf.Pow(charge, 1.2f) * num2;
			if ((Object)(object)HUDManager.Instance != (Object)null)
			{
				if (num3 > 0.7f)
				{
					HUDManager.Instance.ShakeCamera((ScreenShakeType)3);
				}
				else if (num3 > 0.35f)
				{
					HUDManager.Instance.ShakeCamera((ScreenShakeType)1);
				}
				else if (num3 > 0.08f)
				{
					HUDManager.Instance.ShakeCamera((ScreenShakeType)0);
				}
				if (charge > 0.9f && distance < radius * 2.5f)
				{
					HUDManager.Instance.ShakeCamera((ScreenShakeType)2);
				}
			}
			if (num3 > 0.03f)
			{
				FovPunch.Shake(num3, Mathf.Lerp(1f, Mathf.Clamp(Plugin.Instance.FugaShakeSeconds.Value, 1f, 5f), charge) * Mathf.Lerp(0.5f, 1f, num2));
			}
			float num4 = Mathf.Lerp(0f, Plugin.Instance.FugaFovKick.Value, num3);
			if (shooterIsLocal)
			{
				num4 = Mathf.Max(num4, Mathf.Lerp(2f, 5f, charge));
			}
			if (num4 > 0.5f)
			{
				FovPunch.Kick(num4);
			}
			NukeSound.Play(point, charge, distance, lineOfSight, indoors);
			float value = Plugin.Instance.FugaSoundDipSeconds.Value;
			if (value > 0f && charge > 0.5f && distance < radius * 4f)
			{
				SoundDip.Start(value);
			}
		}
	}
	public class SoundDip : MonoBehaviour
	{
		private static SoundDip current;

		private float until;

		public static void Start(float seconds)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((Object)(object)SoundManager.Instance == (Object)null))
				{
					if ((Object)(object)current == (Object)null)
					{
						current = new GameObject("SukunaSoundDip").AddComponent<SoundDip>();
					}
					current.until = Time.unscaledTime + seconds;
					SoundManager.Instance.SetDiageticMixerSnapshot(2, 0.15f);
				}
			}
			catch (Exception ex)
			{
				Plugin.Trace("sound dip FAILED: " + ex.Message);
			}
		}

		private void Update()
		{
			if (Time.unscaledTime < until)
			{
				return;
			}
			try
			{
				if ((Object)(object)SoundManager.Instance != (Object)null)
				{
					SoundManager.Instance.SetDiageticMixerSnapshot(0, 0.6f);
				}
			}
			catch (Exception ex)
			{
				Plugin.Trace("sound dip restore FAILED: " + ex.Message);
			}
			current = null;
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}
	}
	public static class SukunaCombat
	{
		private class Mark
		{
			public EnemyAI Enemy;

			public float Expires;

			public MarkVisual Visual;
		}

		private class Health
		{
			public EnemyAI Enemy;

			public int MaxHp;

			public int UnkillableMax;

			public int UnkillableTaken;

			public float LastHit;

			public HealthBar Bar;
		}

		private static readonly Dictionary<ulong, Mark> marks = new Dictionary<ulong, Mark>();

		private static readonly Dictionary<ulong, Health> health = new Dictionary<ulong, Health>();

		private static readonly Dictionary<ulong, float> lastStun = new Dictionary<ulong, float>();

		private static readonly List<ulong> scratch = new List<ulong>();

		private static Plugin Cfg => Plugin.Instance;

		public static bool IsMarked(EnemyAI enemy)
		{
			if ((Object)(object)enemy != (Object)null && marks.TryGetValue(((NetworkBehaviour)enemy).NetworkObjectId, out var value))
			{
				return Time.time < value.Expires;
			}
			return false;
		}

		public static void SetMark(EnemyAI enemy, bool marked)
		{
			if ((Object)(object)enemy == (Object)null)
			{
				return;
			}
			ulong networkObjectId = ((NetworkBehaviour)enemy).NetworkObjectId;
			if (!marked)
			{
				if (marks.TryGetValue(networkObjectId, out var value) && (Object)(object)value.Visual != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)value.Visual).gameObject);
				}
				marks.Remove(networkObjectId);
				return;
			}
			if (!marks.TryGetValue(networkObjectId, out var value2))
			{
				value2 = new Mark
				{
					Enemy = enemy
				};
				marks[networkObjectId] = value2;
			}
			value2.Expires = Time.time + Cfg.MarkSeconds.Value;
			if ((Object)(object)value2.Visual == (Object)null)
			{
				value2.Visual = MarkVisual.Create(enemy);
			}
		}

		public static bool CanStagger(EnemyAI enemy)
		{
			if ((Object)(object)enemy == (Object)null || Cfg.DismantleStunSeconds.Value <= 0f)
			{
				return false;
			}
			if ((Object)(object)enemy.enemyType != (Object)null && !enemy.enemyType.canBeStunned)
			{
				return false;
			}
			if (lastStun.TryGetValue(((NetworkBehaviour)enemy).NetworkObjectId, out var value))
			{
				return Time.time - value >= Cfg.StunImmunitySeconds.Value;
			}
			return true;
		}

		public static void Stagger(EnemyAI enemy, float seconds, PlayerControllerB by)
		{
			if (!((Object)(object)enemy == (Object)null) && !(seconds <= 0f) && !enemy.isEnemyDead)
			{
				lastStun[((NetworkBehaviour)enemy).NetworkObjectId] = Time.time;
				enemy.SetEnemyStunned(true, seconds, by);
			}
		}

		public static void OnHit(EnemyAI enemy, int hpBefore, int unkillableTaken, int unkillableMax)
		{
			if (!((Object)(object)enemy == (Object)null) && Cfg.ShowEnemyHealthBars.Value)
			{
				ulong networkObjectId = ((NetworkBehaviour)enemy).NetworkObjectId;
				if (!health.TryGetValue(networkObjectId, out var value))
				{
					value = new Health
					{
						Enemy = enemy,
						MaxHp = Mathf.Max(1, hpBefore)
					};
					health[networkObjectId] = value;
				}
				value.MaxHp = Mathf.Max(value.MaxHp, hpBefore);
				if (unkillableMax > 0)
				{
					value.UnkillableMax = unkillableMax;
					value.UnkillableTaken = unkillableTaken;
				}
				value.LastHit = Time.time;
				if ((Object)(object)value.Bar == (Object)null)
				{
					value.Bar = HealthBar.Create(enemy);
				}
			}
		}

		public static void Tick()
		{
			scratch.Clear();
			foreach (KeyValuePair<ulong, Mark> mark in marks)
			{
				Mark value = mark.Value;
				if ((Object)(object)value.Enemy == (Object)null || value.Enemy.isEnemyDead || Time.time >= value.Expires)
				{
					scratch.Add(mark.Key);
				}
			}
			foreach (ulong item in scratch)
			{
				if ((Object)(object)marks[item].Visual != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)marks[item].Visual).gameObject);
				}
				marks.Remove(item);
			}
			scratch.Clear();
			foreach (KeyValuePair<ulong, Health> item2 in health)
			{
				Health value2 = item2.Value;
				float num = Time.time - value2.LastHit;
				if ((Object)(object)value2.Enemy == (Object)null || num > 4.5f || !Cfg.ShowEnemyHealthBars.Value)
				{
					scratch.Add(item2.Key);
				}
				else if (!((Object)(object)value2.Bar == (Object)null))
				{
					float num2 = ((value2.UnkillableMax <= 0) ? ((float)value2.Enemy.enemyHP / (float)value2.MaxHp) : (1f - (float)value2.UnkillableTaken / (float)value2.UnkillableMax));
					if (value2.Enemy.isEnemyDead)
					{
						num2 = 0f;
					}
					float num3 = ((num < 3.5f) ? 1f : (1f - (num - 3.5f)));
					value2.Bar.Set(Mathf.Clamp01(num2), Mathf.Clamp01(num3));
				}
			}
			foreach (ulong item3 in scratch)
			{
				if ((Object)(object)health[item3].Bar != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)health[item3].Bar).gameObject);
				}
				health.Remove(item3);
			}
		}
	}
	public class MarkVisual : MonoBehaviour
	{
		private Transform enemy;

		private float height;

		private LineRenderer a;

		private LineRenderer b;

		private static readonly Color MarkColor = new Color(4f, 0.25f, 0.12f);

		public static MarkVisual Create(EnemyAI enemy)
		{
			//IL_0000: 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_0021: Expected O, but got Unknown
			Material val = SukunaFx.SharedMaterial(MarkColor);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			GameObject val2 = new GameObject("SukunaCutMark");
			MarkVisual markVisual = val2.AddComponent<MarkVisual>();
			markVisual.enemy = ((Component)enemy).transform;
			markVisual.height = EnemyTop(enemy) + 0.35f;
			markVisual.a = Line(val2, val);
			markVisual.b = Line(val2, val);
			return markVisual;
		}

		private static LineRenderer Line(GameObject parent, Material material)
		{
			//IL_0005: 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_0027: Expected O, but got Unknown
			GameObject val = new GameObject("Stroke");
			val.transform.SetParent(parent.transform, false);
			return SukunaFx.AddLine(val, material, 0.08f);
		}

		internal static float EnemyTop(EnemyAI enemy)
		{
			//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_0036: 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)
			float num = 2f;
			bool flag = false;
			Collider[] componentsInChildren = ((Component)enemy).GetComponentsInChildren<Collider>();
			foreach (Collider val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && val.enabled)
				{
					Bounds bounds = val.bounds;
					float num2 = ((Bounds)(ref bounds)).max.y - ((Component)enemy).transform.position.y;
					if (!flag || num2 > num)
					{
						num = num2;
					}
					flag = true;
				}
			}
			return Mathf.Clamp(num, 0.5f, 12f);
		}

		private void Update()
		{
			//IL_0041: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: 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_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: 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_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: 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_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)
			if ((Object)(object)enemy == (Object)null)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			Camera val = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.activeCamera : null);
			((Component)this).transform.position = enemy.position + Vector3.up * height;
			if ((Object)(object)val != (Object)null)
			{
				((Component)this).transform.rotation = Quaternion.LookRotation(((Component)this).transform.position - ((Component)val).transform.position);
			}
			float num = Time.time * 60f;
			float num2 = 1f + 0.2f * Mathf.Sin(Time.time * 9f);
			Vector3 val2 = Quaternion.Euler(0f, 0f, num + 45f) * Vector3.up * 0.3f;
			Vector3 val3 = Quaternion.Euler(0f, 0f, num - 45f) * Vector3.up * 0.3f;
			SukunaFx.SetSegment(a, -val2, val2);
			SukunaFx.SetSegment(b, -val3, val3);
			a.widthMultiplier = 0.08f * num2;
			b.widthMultiplier = 0.08f * num2;
		}
	}
	public class HealthBar : MonoBehaviour
	{
		private Transform enemy;

		private float height;

		private LineRenderer back;

		private LineRenderer fill;

		private float shown = 1f;

		private const float Width = 1.1f;

		public static HealthBar Create(EnemyAI enemy)
		{
			//IL_000f: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			Material val = SukunaFx.SharedMaterial(new Color(0.03f, 0.02f, 0.02f));
			Material val2 = SukunaFx.SharedMaterial(new Color(2.2f, 0.12f, 0.08f));
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				return null;
			}
			GameObject val3 = new GameObject("SukunaHealthBar");
			HealthBar healthBar = val3.AddComponent<HealthBar>();
			healthBar.enemy = ((Component)enemy).transform;
			healthBar.height = MarkVisual.EnemyTop(enemy) + 0.75f;
			healthBar.back = Flat(val3, "Back", val, 0.11f);
			healthBar.fill = Flat(val3, "Fill", val2, 0.07f);
			return healthBar;
		}

		private static LineRenderer Flat(GameObject parent, string name, Material material, float width)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent.transform, false);
			LineRenderer obj = SukunaFx.AddLine(val, material, width);
			obj.widthCurve = AnimationCurve.Constant(0f, 1f, 1f);
			obj.positionCount = 2;
			return obj;
		}

		public void Set(float fraction, float alpha)
		{
			//IL_0053: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: 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_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: 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_012c: 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_013b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)enemy == (Object)null))
			{
				shown = Mathf.MoveTowards(shown, fraction, Time.deltaTime * 2f);
				Camera val = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.activeCamera : null);
				((Component)this).transform.position = enemy.position + Vector3.up * height;
				Vector3 val2 = (((Object)(object)val != (Object)null) ? ((Component)val).transform.right : Vector3.right);
				Vector3 val3 = -val2 * 0.55f;
				back.SetPosition(0, val3);
				back.SetPosition(1, -val3);
				fill.SetPosition(0, val3);
				fill.SetPosition(1, val3 + val2 * (1.1f * shown));
				if ((Object)(object)val != (Object)null)
				{
					Transform transform = ((Component)fill).transform;
					Vector3 position = ((Component)this).transform.position;
					Vector3 val4 = ((Component)val).transform.position - ((Component)this).transform.position;
					transform.position = position + ((Vector3)(ref val4)).normalized * 0.02f;
				}
				back.widthMultiplier = 0.11f * alpha;
				fill.widthMultiplier = 0.07f * alpha;
				((Renderer)fill).enabled = shown > 0.001f;
			}
		}
	}
	public class SukunaController : MonoBehaviour
	{
		private int dismantleCharges = -1;

		private float dismantleRechargeAt;

		private float nextDismantleShot;

		private float nextCleaveTime;

		private bool shownControlsTip;

		private bool hyperHeldLastFrame;

		private float noFallDamageUntil;

		private float toggleHeldSince = -1f;

		private bool toggleFired;

		private static readonly Dictionary<EnemyAI, int> unkillableDamage = new Dictionary<EnemyAI, int>();

		private bool reportedUpdateError;

		private bool reportedHudError;

		private static Plugin Cfg => Plugin.Instance;

		private void Start()
		{
			SukunaAudio.Init();
			NukeSound.Init();
			try
			{
				FireSheets.Build();
			}
			catch (Exception ex)
			{
				Plugin.Trace("fire sheets failed: " + ex.Message);
			}
		}

		private void Update()
		{
			Interlocked.Increment(ref Plugin.Frames);
			Plugin.Section = "mod update";
			try
			{
				SukunaHud.TickFlash();
				Tick();
			}
			catch (Exception ex)
			{
				if (!reportedUpdateError)
				{
					Plugin.Log.LogError((object)ex);
				}
				if (!reportedUpdateError)
				{
					Plugin.Trace("update error: " + ex.Message);
				}
				reportedUpdateError = true;
			}
			Plugin.Section = "mod hud";
			try
			{
				UpdateHud();
			}
			catch (Exception ex2)
			{
				if (!reportedHudError)
				{
					Plugin.Log.LogError((object)ex2);
				}
				if (!reportedHudError)
				{
					Plugin.Trace("hud error: " + ex2);
				}
				reportedHudError = true;
				SukunaHud.Hide("error");
				try
				{
					SukunaHud.DumpOnFailure();
				}
				catch
				{
				}
			}
			Plugin.Section = "game";
		}

		private void Tick()
		{
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			SukunaNet.Tick();
			SukunaKnockback.Tick();
			SukunaCombat.Tick();
			RechargeDismantle();
			FovPunch.Tick();
			Hitstop.Tick();
			PostFx.Tick();
			FovPunch.Squeeze = ((SukunaFuga.CurrentState != SukunaFuga.State.Idle) ? (5f * Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(0.5f, 1f, SukunaFuga.Charge))) : 0f);
			if (FovPunch.Squeeze > 0f)
			{
				FovPunch.Hook();
			}
			PlayerControllerB val = LocalPlayer();
			if ((Object)(object)val == (Object)null)
			{
				hyperHeldLastFrame = false;
				noFallDamageUntil = 0f;
				SukunaFuga.Reset();
				SukunaRct.Reset();
				return;
			}
			Keyboard current = Keyboard.current;
			UpdatePowerToggle(val, current);
			if (!Cfg.PowersEnabled.Value)
			{
				hyperHeldLastFrame = false;
				noFallDamageUntil = 0f;
				if (SukunaFuga.CurrentState != SukunaFuga.State.Idle)
				{
					SukunaNet.FugaState(val, SukunaFuga.State.Idle, 0f);
				}
				SukunaFuga.Reset();
				SukunaRct.Reset();
				return;
			}
			ShowControlsTipOnce();
			bool flag = current != null && CanUseAbilities(val);
			bool flag2 = flag && ((ButtonControl)current[Cfg.HyperSpeedKey.Value]).isPressed;
			if (hyperHeldLastFrame && !flag2)
			{
				noFallDamageUntil = Time.time + Cfg.AfterHyperSeconds.Value;
			}
			hyperHeldLastFrame = flag2;
			if (flag2 || Time.time < noFallDamageUntil)
			{
				PreventFallDamage(val);
			}
			SukunaFuga.Update(val, current, flag);
			SukunaRct.Update(val, current, flag);
			if (!flag)
			{
				return;
			}
			if (((ButtonControl)current[Cfg.DismantleKey.Value]).wasPressedThisFrame && dismantleCharges > 0 && Time.time >= nextDismantleShot)
			{
				dismantleCharges--;
				nextDismantleShot = Time.time + Cfg.DismantleMinInterval.Value;
				if (dismantleRechargeAt <= 0f)
				{
					dismantleRechargeAt = Time.time + Cfg.DismantleCooldown.Value;
				}
				Dismantle(val);
			}
			if (((ButtonControl)current[Cfg.CleaveKey.Value]).wasPressedThisFrame && Time.time >= nextCleaveTime)
			{
				nextCleaveTime = Time.time + Cfg.CleaveCooldown.Value;
				Cleave(val);
			}
			if (flag2)
			{
				HyperSpeedMove(val);
			}
		}

		private void RechargeDismantle()
		{
			int num = Mathf.Max(1, Cfg.DismantleCharges.Value);
			if (dismantleCharges < 0 || dismantleCharges > num)
			{
				dismantleCharges = num;
			}
			if (dismantleCharges >= num)
			{
				dismantleRechargeAt = 0f;
				return;
			}
			if (dismantleRechargeAt <= 0f)
			{
				dismantleRechargeAt = Time.time + Cfg.DismantleCooldown.Value;
			}
			while (dismantleCharges < num && Time.time >= dismantleRechargeAt)
			{
				dismantleCharges++;
				dismantleRechargeAt = ((dismantleCharges < num) ? (dismantleRechargeAt + Cfg.DismantleCooldown.Value) : 0f);
			}
		}

		private void UpdateHud()
		{
			//IL_00b3: 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_017b: Unknown result type (might be due to invalid IL or missing references)
			PlayerControllerB val = LocalPlayer();
			string text = ((Cfg == null) ? "no config" : ((!Cfg.PowersEnabled.Value) ? "powers off" : (((Object)(object)val == (Object)null) ? "no local player" : (val.inTerminalMenu ? "terminal" : (((Object)(object)val.quickMenuManager != (Object)null && val.quickMenuManager.isMenuOpen) ? "pause menu" : null)))));
			if (text != null)
			{
				SukunaHud.Hide(text);
				return;
			}
			string cooldownText = "";
			if (Cfg.ShowCooldowns.Value)
			{
				cooldownText = DismantleLine() + "\n" + CooldownLine(Cfg.CleaveKey.Value, "Cleave", nextCleaveTime - Time.time) + "\n" + CooldownLine(Cfg.FugaKey.Value, "Fuga", SukunaFuga.CooldownLeft);
			}
			float sinceOpen = SukunaFuga.SinceOpen;
			float openAlpha = ((sinceOpen < 0f || sinceOpen > 1.6f) ? 0f : ((sinceOpen < 0.15f) ? (sinceOpen / 0.15f) : (1f - Mathf.Clamp01((sinceOpen - 0.8f) / 0.8f))));
			bool showBar = SukunaFuga.CurrentState != SukunaFuga.State.Idle;
			float charge = SukunaFuga.Charge;
			string barText = ((SukunaFuga.CurrentState == SukunaFuga.State.Charging) ? $"FUGA  {charge * 100f:0}%" : $"FUGA  {charge * 100f:0}%    [LMB] fire    [{Cfg.FugaKey.Value}] cancel");
			SukunaHud.Show(cooldownText, openAlpha, showBar, charge, barText, SukunaRct.HudText(val));
		}

		private string DismantleLine()
		{
			//IL_00c4: 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)
			int num = Mathf.Max(1, Cfg.DismantleCharges.Value);
			int num2 = Mathf.Clamp(dismantleCharges, 0, num);
			string text = "<color=#FF5A4D>" + new string('I', num2) + "</color><color=#59595999>" + new string('I', num - num2) + "</color>";
			string text2 = ((num2 >= num) ? "<color=#FF5A4D>READY</color>" : $"<color=#BFBFBFD9>{Mathf.Max(0f, dismantleRechargeAt - Time.time):0.0}s</color>");
			string text3 = ((num2 > 0) ? $"<color=#FF5A4D>[{Cfg.DismantleKey.Value}] Dismantle</color>" : $"<color=#BFBFBFD9>[{Cfg.DismantleKey.Value}] Dismantle</color>");
			return text3 + "  <b>" + text + "</b>  " + text2;
		}

		private static string CooldownLine(Key key, string name, float left)
		{
			//IL_0025: 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)
			if (!(left <= 0f))
			{
				return $"<color=#BFBFBFD9>[{key}] {name}  {left:0.0}s</color>";
			}
			return $"<color=#FF5A4D>[{key}] {name}  READY</color>";
		}

		private static PlayerControllerB LocalPlayer()
		{
			if ((Object)(object)GameNetworkManager.Instance == (Object)null)
			{
				return null;
			}
			PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController;
			if ((Object)(object)localPlayerController == (Object)null || !localPlayerController.isPlayerControlled || localPlayerController.isPlayerDead)
			{
				return null;
			}
			return localPlayerController;
		}

		private static bool CanUseAbilities(PlayerControllerB player)
		{
			if (player.inTerminalMenu || player.isTypingChat)
			{
				return false;
			}
			if ((Object)(object)player.quickMenuManager != (Object)null && player.quickMenuManager.isMenuOpen)
			{
				return false;
			}
			if (player.inSpecialInteractAnimation || player.isClimbingLadder)
			{
				return false;
			}
			return true;
		}

		private static void PreventFallDamage(PlayerControllerB player)
		{
			player.takingFallDamage = false;
			if (player.fallValueUncapped < -30f)
			{
				player.fallValueUncapped = -30f;
			}
		}

		private void UpdatePowerToggle(PlayerControllerB player, Keyboard keyboard)
		{
			//IL_001e: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: 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_0164: Unknown result type (might be due to invalid IL or missing references)
			if (keyboard == null || player.isTypingChat || player.inTerminalMenu || !((ButtonControl)keyboard[Cfg.ToggleKey1.Value]).isPressed || !((ButtonControl)keyboard[Cfg.ToggleKey2.Value]).isPressed || !((ButtonControl)keyboard[Cfg.ToggleKey3.Value]).isPressed)
			{
				toggleHeldSince = -1f;
				toggleFired = false;
				return;
			}
			if (toggleHeldSince < 0f)
			{
				toggleHeldSince = Time.time;
			}
			if (toggleFired || Time.time - toggleHeldSince < Cfg.ToggleHoldSeconds.Value)
			{
				return;
			}
			toggleFired = true;
			bool flag = !Cfg.PowersEnabled.Value;
			Cfg.PowersEnabled.Value = flag;
			if (!((Object)(object)HUDManager.Instance == (Object)null))
			{
				if (flag)
				{
					shownControlsTip = true;
					HUDManager.Instance.DisplayTip("Sukuna", "Powers ON. " + ControlsText(), false, false, "LC_Tip1");
				}
				else
				{
					HUDManager.Instance.DisplayTip("Sukuna", $"Powers OFF. Hold [{Cfg.ToggleKey1.Value}] + [{Cfg.ToggleKey2.Value}] + [{Cfg.ToggleKey3.Value}] to turn them back on.", false, false, "LC_Tip1");
				}
			}
		}

		private void ShowControlsTipOnce()
		{
			if (!shownControlsTip && !((Object)(object)HUDManager.Instance == (Object)null))
			{
				shownControlsTip = true;
				HUDManager.Instance.DisplayTip("Ryomen Sukuna", ControlsText(), false, false, "LC_Tip1");
			}
		}

		private static string ControlsText()
		{
			//IL_0017: 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_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			return $"[{Cfg.DismantleKey.Value}] Dismantle   [{Cfg.CleaveKey.Value}] Cleave   Hold [{Cfg.FugaKey.Value}] Fuga (LMB fires)   Hold [{Cfg.RctKey.Value}] Heal   Hold [{Cfg.HyperSpeedKey.Value}] Hyper speed";
		}

		private void Dismantle(PlayerControllerB player)
		{
			//IL_001f: 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_004a: 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_0078: 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_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: 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_00a6: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)player.gameplayCamera).transform;
			float value = Cfg.DismantleRange.Value;
			float num = value;
			RaycastHit val = default(RaycastHit);
			bool flag = Physics.Raycast(transform.position, transform.forward, ref val, value, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1);
			if (flag)
			{
				num = ((RaycastHit)(ref val)).distance;
			}
			RaycastHit[] hits = Physics.SphereCastAll(transform.position, 0.7f, transform.forward, num, -1, (QueryTriggerInteraction)2);
			HitAll(player, hits, SlashKind.Dismantle, Cfg.DismantleDamage.Value, transform.forward);
			SukunaNet.Slash(SlashKind.Dismantle, transform.position + transform.forward * 0.8f, transform.forward, transform.up, num, Random.Range(int.MinValue, int.MaxValue), flag, ((RaycastHit)(ref val)).point, ((RaycastHit)(ref val)).normal);
		}

		private void Cleave(PlayerControllerB player)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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_0072: 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_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: 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)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: 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_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)player.gameplayCamera).transform;
			float value = Cfg.CleaveRadius.Value;
			float num = Mathf.Max(Cfg.CleaveReach.Value, value);
			Vector3 val = transform.position + transform.forward * (value * 0.75f);
			Vector3 val2 = transform.position + transform.forward * 0.5f;
			Vector3 val3 = transform.position + transform.forward * Mathf.Max(0.5f, num - value);
			Collider[] colliders = Physics.OverlapCapsule(val2, val3, value, -1, (QueryTriggerInteraction)2);
			if (HitAll(player, colliders, SlashKind.Cleave, Cfg.CleaveDamage.Value, transform.forward) > 0 && (Object)(object)HUDManager.Instance != (Object)null)
			{
				HUDManager.Instance.ShakeCamera((ScreenShakeType)0);
			}
			int collidersAndRoomMaskAndDefault = StartOfRound.Instance.collidersAndRoomMaskAndDefault;
			RaycastHit val4 = default(RaycastHit);
			bool num2 = Physics.Raycast(transform.position, transform.forward, ref val4, num, collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1);
			float reach = (num2 ? Mathf.Max(1f, ((RaycastHit)(ref val4)).distance) : num);
			bool hitSurface = num2 || Physics.Raycast(val, Vector3.down, ref val4, 4f, collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1);
			SukunaNet.Slash(SlashKind.Cleave, transform.position + transform.forward * 0.6f, transform.forward, transform.up, reach, Random.Range(int.MinValue, int.MaxValue), hitSurface, ((RaycastHit)(ref val4)).point, ((RaycastHit)(ref val4)).normal);
		}

		private static void HyperSpeedMove(PlayerControllerB player)
		{
			//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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_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_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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_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_00ac: 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_00b7: 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_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_00cc: 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_00e6: 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_0066: 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)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)player.gameplayCamera).transform;
			Vector2 val = Vector2.zero;
			if ((Object)(object)IngamePlayerSettings.Instance != (Object)null && (Object)(object)IngamePlayerSettings.Instance.playerInput != (Object)null)
			{
				InputAction val2 = IngamePlayerSettings.Instance.playerInput.actions.FindAction("Move", false);
				if (val2 != null)
				{
					val = val2.ReadValue<Vector2>();
				}
			}
			if (((Vector2)(ref val)).sqrMagnitude < 0.01f)
			{
				val = Vector2.up;
			}
			Vector3 val3 = Vector3.ProjectOnPlane(transform.forward, Vector3.up);
			Vector3 normalized = ((Vector3)(ref val3)).normalized;
			val3 = Vector3.ProjectOnPlane(transform.right, Vector3.up);
			Vector3 normalized2 = ((Vector3)(ref val3)).normalized;
			val3 = normalized * val.y + normalized2 * val.x;
			Vector3 normalized3 = ((Vector3)(ref val3)).normalized;
			player.thisController.Move(normalized3 * Cfg.HyperSpeed.Value * Time.deltaTime);
			player.sprintMeter = Mathf.Max(player.sprintMeter, 0.5f);
		}

		private static int HitAll(PlayerControllerB player, RaycastHit[] hits, SlashKind kind, int force, Vector3 direction)
		{
			//IL_002a: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			Collider[] array = (Collider[])(object)new Collider[hits.Length];
			for (int i = 0; i < hits.Length; i++)
			{
				array[i] = ((RaycastHit)(ref hits[i])).collider;
			}
			return HitAll(player, array, kind, force, direction);
		}

		internal static void FugaBlastDamage(PlayerControllerB shooter, Vector3 center, float charge)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			float num = SukunaFuga.Radius(charge);
			int force = Mathf.RoundToInt(Mathf.Lerp((float)Cfg.FugaMinDamage.Value, (float)Cfg.FugaMaxDamage.Value, charge));
			Collider[] colliders = Physics.OverlapSphere(center, num, -1, (QueryTriggerInteraction)2);
			HitAll(shooter, colliders, SlashKind.Cleave, force, Vector3.zero, blast: true, center, Cfg.FugaKnockback.Value * Mathf.Lerp(0.4f, 1f, charge), num);
			float num2 = Mathf.Lerp(0.5f, 1f, charge) * Mathf.Max(0f, Cfg.FugaStunSeconds.Value);
			if (num2 <= 0f)
			{
				return;
			}
			HashSet<EnemyAI> hashSet = new HashSet<EnemyAI>();
			Collider[] array = Physics.OverlapSphere(center, num * 2.5f, -1, (QueryTriggerInteraction)2);
			EnemyAICollisionDetect val2 = default(EnemyAICollisionDetect);
			foreach (Collider val in array)
			{
				if (!((Object)(object)val == (Object)null) && ((Component)val).TryGetComponent<EnemyAICollisionDetect>(ref val2) && !((Object)(object)val2.mainScript == (Object)null))
				{
					EnemyAI mainScript = val2.mainScript;
					if (!mainScript.isEnemyDead && hashSet.Add(mainScript) && !(Vector3.Distance(((Component)mainScript).transform.position, center) <= num))
					{
						SukunaNet.EnemyStun(mainScript, shooter, num2);
					}
				}
			}
		}

		private static int HitAll(PlayerControllerB player, Collider[] colliders, SlashKind kind, int force, Vector3 direction, bool blast = false, Vector3 blastCenter = default(Vector3), float blastPush = 0f, float blastRadius = 1f)
		{
			//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_0123: Unknown result type (might be due to invalid IL or missing references)
			//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_012f: 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)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: 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_00fc: 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_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0302: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Unknown result type (might be due to invalid IL or missing references)
			//IL_030b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_035b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0366: Unknown result type (might be due to invalid IL or missing references)
			//IL_036b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0370: Unknown result type (might be due to invalid IL or missing references)
			//IL_0375: Unknown result type (might be due to invalid IL or missing references)
			//IL_037a: Unknown result type (might be due to invalid IL or missing references)
			//IL_039c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: 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_0391: Unknown result type (might be due to invalid IL or missing references)
			//IL_0396: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)player.gameplayCamera).transform.position;
			int collidersAndRoomMaskAndDefault = StartOfRound.Instance.collidersAndRoomMaskAndDefault;
			HashSet<Object> hashSet = new HashSet<Object>();
			int num = 0;
			IHittable val2 = default(IHittable);
			RaycastHit val5 = default(RaycastHit);
			foreach (Collider val in colliders)
			{
				if ((Object)(object)val == (Object)null || ((Component)val).transform.IsChildOf(((Component)player).transform) || !((Component)val).TryGetComponent<IHittable>(ref val2))
				{
					continue;
				}
				Object item = (Object)(object)val;
				EnemyAI val3 = null;
				EnemyAICollisionDetect val4 = (EnemyAICollisionDetect)(object)((val2 is EnemyAICollisionDetect) ? val2 : null);
				if (val4 != null && (Object)(object)val4.mainScript != (Object)null)
				{
					val3 = val4.mainScript;
					if (val3.isEnemyDead)
					{
						continue;
					}
					item = (Object)(object)val3;
				}
				if ((val2 is PlayerControllerB && (blast || !Plugin.Instance.HitPlayers.Value)) || (blast && (Object)(object)val3 == (Object)null) || !hashSet.Add(item))
				{
					continue;
				}
				Bounds bounds;
				if (blast)
				{
					bounds = val.bounds;
					direction = ((Bounds)(ref bounds)).center - blastCenter;
					direction = ((((Vector3)(ref direction)).sqrMagnitude > 0.01f) ? ((Vector3)(ref direction)).normalized : Vector3.up);
				}
				else
				{
					bounds = val.bounds;
					if (Physics.Linecast(position, ((Bounds)(ref bounds)).center, ref val5, collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1) && !((Component)((RaycastHit)(ref val5)).collider).transform.IsChildOf(((Component)val).transform.root))
					{
						continue;
					}
				}
				if ((Object)(object)val3 == (Object)null)
				{
					val2.Hit(force, direction, player, true, 1);
					num++;
					continue;
				}
				int num2 = force;
				bool marked = false;
				bool consumedMark = false;
				float stun = 0f;
				if (!blast && kind == SlashKind.Dismantle)
				{
					marked = true;
					if (SukunaCombat.CanStagger(val3))
					{
						stun = Cfg.DismantleStunSeconds.Value;
					}
				}
				else if (!blast && kind == SlashKind.Cleave && SukunaCombat.IsMarked(val3))
				{
					consumedMark = true;
					num2 += Mathf.Max(0, Cfg.CleaveMarkBonus.Value);
					if ((Object)(object)HUDManager.Instance != (Object)null)
					{
						HUDManager.Instance.ShakeCamera((ScreenShakeType)1);
					}
				}
				int enemyHP = val3.enemyHP;
				int num3;
				int num4;
				if ((Object)(object)val3.enemyType != (Object)null)
				{
					num3 = ((!val3.enemyType.canDie) ? 1 : 0);
					if (num3 != 0)
					{
						num4 = UnkillableHP(val3);
						goto IL_0235;
					}
				}
				else
				{
					num3 = 0;
				}
				num4 = 0;
				goto IL_0235;
				IL_0235:
				int num5 = num4;
				int unkillableTaken = 0;
				if (num3 != 0)
				{
					unkillableDamage.TryGetValue(val3, out var value);
					unkillableTaken = Mathf.Min(value + num2, num5);
				}
				val2.Hit(num2, direction, player, true, 1);
				num++;
				if (blast)
				{
					bounds = val.bounds;
					float num6 = 1f - 0.5f * Mathf.Clamp01(Vector3.Distance(((Bounds)(ref bounds)).center, blastCenter) / Mathf.Max(0.1f, blastRadius));
					Vector3 val6 = Vector3.ProjectOnPlane(direction, Vector3.up);
					if (blastPush > 0f && ((Vector3)(ref val6)).sqrMagnitude > 0.001f)
					{
						SukunaNet.Knockback(val3, ((Vector3)(ref val6)).normalized * blastPush * num6);
					}
				}
				if (blast)
				{
					SukunaNet.EnemyHit(val3, player, enemyHP, unkillableTaken, num5);
				}
				else
				{
					EnemyAI enemy = val3;
					bounds = val.bounds;
					SukunaNet.EnemyHit(kind, enemy, ((Bounds)(ref bounds)).center, direction, Random.Range(int.MinValue, int.MaxValue), player, marked, consumedMark, stun, enemyHP, unkillableTaken, num5);
				}
				if (!blast && kind == SlashKind.Cleave && Cfg.CleaveKnockback.Value > 0f)
				{
					Vector3 val7 = Vector3.ProjectOnPlane(((Component)val3).transform.position - ((Component)player).transform.position, Vector3.up);
					if (((Vector3)(ref val7)).sqrMagnitude < 0.01f)
					{
						val7 = Vector3.ProjectOnPlane(direction, Vector3.up);
					}
					SukunaNet.Knockback(val3, ((Vector3)(ref val7)).normalized * Cfg.CleaveKnockback.Value);
				}
				if (num3 != 0)
				{
					DamageUnkillable(val3, num2);
				}
			}
			return num;
		}

		private static void DamageUnkillable(EnemyAI enemy, int force)
		{
			unkillableDamage.TryGetValue(enemy, out var value);
			value += force;
			if (value < UnkillableHP(enemy))
			{
				unkillableDamage[enemy] = value;
				return;
			}
			unkillableDamage.Remove(enemy);
			List<EnemyAI> list = new List<EnemyAI>();
			foreach (EnemyAI key in unkillableDamage.Keys)
			{
				if ((Object)(object)key == (Object)null)
				{
					list.Add(key);
				}
			}
			foreach (EnemyAI item in list)
			{
				unkillableDamage.Remove(item);
			}
			RemoveEnemy(enemy);
		}

		private static int UnkillableHP(EnemyAI enemy)
		{
			if (enemy is SpringManAI)
			{
				return Cfg.CoilHeadHP.Value;
			}
			if (enemy is JesterAI)
			{
				return Cfg.JesterHP.Value;
			}
			return Cfg.DefaultUnkillableHP.Value;
		}

		private static void RemoveEnemy(EnemyAI enemy)
		{
			if (((NetworkBehaviour)enemy).IsServer)
			{
				if (enemy.enemyType.canBeDestroyed)
				{
					enemy.KillEnemy(true);
				}
				else if ((Object)(object)enemy.thisNetworkObject != (Object)null && enemy.thisNetworkObject.IsSpawned)
				{
					enemy.thisNetworkObject.Despawn(true);
				}
			}
			else if (!enemy.enemyType.canBeDestroyed)
			{
				Plugin.Log.LogWarning((object)(enemy.enemyType.enemyName + " can only be removed by the host."));
			}
			else
			{
				enemy.KillEnemyServerRpc(true);
			}
		}
	}
	public static class SukunaFuga
	{
		public enum State : byte
		{
			Idle,
			Charging,
			Ready
		}

		private const float MinCharge = 0.05f;

		private const float MaxDistance = 250f;

		private static State state;

		private static float charge;

		private static float nextFugaTime;

		private static float openTextAt = -10f;

		private static bool swallowClick;

		private static FugaBow localBow;

		private static readonly Dictionary<int, FugaBow> remoteBows = new Dictionary<int, FugaBow>();

		private static Plugin Cfg => Plugin.Instance;

		public static bool BlocksItemUse
		{
			get
			{
				if (state == State.Idle)
				{
					return swallowClick;
				}
				return true;
			}
		}

		public static float CooldownLeft => nextFugaTime - Time.time;

		public static State CurrentState => state;

		public static float Charge => charge;

		public static float SinceOpen => Time.time - openTextAt;

		public static float Radius(float charge)
		{
			return Mathf.Lerp(3f, Mathf.Max(3f, Cfg.FugaMaxRadius.Value), charge);
		}

		public static void Update(PlayerControllerB player, Keyboard keyboard, bool canAct)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			Mouse current = Mouse.current;
			if (swallowClick && (current == null || !current.leftButton.isPressed))
			{
				swallowClick = false;
			}
			if (!canAct)
			{
				if (state != State.Idle)
				{
					Cancel(player);
				}
				return;
			}
			bool wasPressedThisFrame = ((ButtonControl)keyboard[Cfg.FugaKey.Value]).wasPressedThisFrame;
			switch (state)
			{
			case State.Idle:
				if (wasPressedThisFrame && Time.time >= nextFugaTime)
				{
					state = State.Charging;
					charge = 0f;
					openTextAt = Time.time;
					localBow = FugaBow.Create(((Component)player.gameplayCamera).transform, firstPerson: true);
					SukunaNet.FugaState(player, state, charge);
				}
				break;
			case State.Charging:
				if (((ButtonControl)keyboard[Cfg.FugaKey.Value]).isPressed)
				{
					charge = Mathf.Clamp01(charge + Time.deltaTime / Mathf.Max(0.1f, Cfg.FugaChargeSeconds.Value));
					break;
				}
				state = State.Ready;
				SukunaNet.FugaState(player, state, charge);
				break;
			case State.Ready:
				if (wasPressedThisFrame)
				{
					Cancel(player);
					return;
				}
				break;
			}
			if ((Object)(object)localBow != (Object)null)
			{
				localBow.Charge = charge;
			}
			if (state != State.Idle && current != null && current.leftButton.wasPressedThisFrame && charge >= 0.05f)
			{
				Fire(player);
			}
		}

		public static void Reset()
		{
			state = State.Idle;
			charge = 0f;
			swallowClick = false;
			if ((Object)(object)localBow != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)localBow).gameObject);
			}
			localBow = null;
		}

		private static void Cancel(PlayerControllerB player)
		{
			Reset();
			SukunaNet.FugaState(player, State.Idle, 0f);
		}

		private static void Fire(PlayerControllerB player)
		{
			//IL_000d: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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_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_003c: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: 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_007f: 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_0091: 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_00b7: 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_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_0155: 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_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: 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)
			//IL_0111: 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)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)player.gameplayCamera).transform;
			Vector3 origin = transform.position + transform.forward * 0.9f - transform.up * 0.12f;
			int collidersAndRoomMaskAndDefault = StartOfRound.Instance.collidersAndRoomMaskAndDefault;
			int mask = LayerMask.GetMask(new string[1] { "Enemies" });
			Vector3 target = transform.position + transform.forward * 250f;
			Vector3 normal = -transform.forward;
			bool hitSurface = false;
			float num = 250f;
			RaycastHit val = default(RaycastHit);
			if (Physics.Raycast(transform.position, transform.forward, ref val, 250f, collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1))
			{
				num = ((RaycastHit)(ref val)).distance;
				target = ((RaycastHit)(ref val)).point;
				normal = ((RaycastHit)(ref val)).normal;
				hitSurface = true;
			}
			RaycastHit val2 = default(RaycastHit);
			if (mask != 0 && Physics.SphereCast(transform.position, 0.3f, transform.forward, ref val2, num, mask, (QueryTriggerInteraction)2) && ((RaycastHit)(ref val2)).distance > 0.5f)
			{
				target = transform.position + transform.forward * ((RaycastHit)(ref val2)).distance;
				normal = -transform.forward;
				hitSurface = false;
			}
			float num2 = charge;
			Reset();
			swallowClick = true;
			nextFugaTime = Time.time + Cfg.FugaCooldown.Value;
			SukunaNet.FugaFire(player, origin, target, normal, hitSurface, num2, player.isInsideFactory);
		}

		public static void Launch(PlayerControllerB shooter, bool dealsDamage, Vector3 origin, Vector3 target, Vector3 normal, bool hitSurface, float charge, bool indoors)
		{
			//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_000a: 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)
			RemoveRemoteBow(shooter);
			FugaArrow.Create(shooter, dealsDamage, origin, target, normal, hitSurface, charge, indoors);
			SukunaAudio.PlayLaunch(origin, charge);
		}

		public static void ApplyRemoteState(PlayerControllerB player, State newState, float newCharge)
		{
			int key = (int)player.playerClientId;
			if (newState == State.Idle || player.isPlayerDead)
			{
				RemoveRemoteBow(player);
				return;
			}
			if (!remoteBows.TryGetValue(key, out var value) || (Object)(object)value == (Object)null)
			{
				value = FugaBow.Create(((Component)player.gameplayCamera).transform, firstPerson: false);
				remoteBows[key] = value;
			}
			value.Charge = newCharge;
			value.Growing = newState == State.Charging;
		}

		private static void RemoveRemoteBow(PlayerControllerB player)
		{
			int key = (int)player.playerClientId;
			if (remoteBows.TryGetValue(key, out var value) && (Object)(object)value != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)value).gameObject);
			}
			remoteBows.Remove(key);
		}
	}
	public class FugaBow : MonoBehaviour
	{
		public float Charge;

		public bool Growing;

		private LineRenderer bow;

		private LineRenderer bowString;

		private LineRenderer shaft;

		private LineRenderer head;

		private readonly List<LineRenderer> flames = new List<LineRenderer>();

		private SukunaLight glow;

		private const int BowPoints = 17;

		private static readonly Color BowColor = new Color(3f, 0.55f, 0.08f);

		private static readonly Color StringColor = new Color(2.5f, 1.2f, 0.4f);

		private static readonly Color ShaftColor = new Color(5f, 2.4f, 0.6f);

		private static readonly Color FlameColor = new Color(4f, 1.1f, 0.12f);

		private static readonly Color HeadColor = new Color(8f, 6f, 3f);

		private AudioSource rush;

		private AudioSource whistle;

		public static FugaBow Create(Transform camera, bool firstPerson)
		{
			//IL_0000: 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_002b: 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_0043: 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_0078: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)SukunaFx.SharedMaterial(BowColor) == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject("SukunaFugaBow");
			val.transform.SetParent(camera, false);
			val.transform.localPosition = (firstPerson ? new Vector3(0.02f, -0.2f, 0.55f) : new Vector3(0.1f, -0.25f, 0.45f));
			val.transform.localRotation = Quaternion.Euler(0f, 0f, -18f);
			FugaBow fugaBow = val.AddComponent<FugaBow>();
			fugaBow.Build();
			return fugaBow;
		}

		private void Build()
		{
			//IL_0007: 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_003a: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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)
			//IL_0075: Expected O, but got Unknown
			//IL_0