Decompiled source of ResonanceBoots v1.2.0

plugins/ResonanceBoots.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Imui.Controls;
using Imui.Core;
using Imui.Rendering;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using WKLib.API;
using WKLib.API.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace ResonanceBoots;

public class BootsController : MonoBehaviour
{
	public const string EnabledKey = "resonance-enabled";

	private static readonly FieldRef<ENT_Player, Vector3> Vel = AccessTools.FieldRefAccess<ENT_Player, Vector3>("vel");

	private static readonly FieldRef<ENT_Player, Vector3> LastVel = AccessTools.FieldRefAccess<ENT_Player, Vector3>("lastVel");

	private static readonly FieldRef<ENT_Player, bool> IsGroundedField = AccessTools.FieldRefAccess<ENT_Player, bool>("isGrounded");

	private static readonly FieldRef<ENT_Player, float> ForceAirbornTime = AccessTools.FieldRefAccess<ENT_Player, float>("forceAirbornTime");

	private static readonly FieldRef<ENT_Player, bool> HasJumped = AccessTools.FieldRefAccess<ENT_Player, bool>("hasJumped");

	private static readonly FieldRef<ENT_Player, float> FallStartHeight = AccessTools.FieldRefAccess<ENT_Player, float>("fallStartHeight");

	private static readonly FieldRef<ENT_Player, bool> Falling = AccessTools.FieldRefAccess<ENT_Player, bool>("falling");

	private static readonly FieldRef<ENT_Player, float> CurFallDistance = AccessTools.FieldRefAccess<ENT_Player, float>("curFallDistance");

	private static readonly FieldRef<ENT_Player, bool> IsSwimming = AccessTools.FieldRefAccess<ENT_Player, bool>("isSwimming");

	private static readonly FieldRef<ENT_Player, bool> CutsceneMode = AccessTools.FieldRefAccess<ENT_Player, bool>("cutsceneMode");

	private static readonly FieldRef<ENT_Player, Vector3> CorrectedVelocity = AccessTools.FieldRefAccess<ENT_Player, Vector3>("correctedVelocity");

	private static readonly FieldInfo ConsoleInstance = AccessTools.Field(typeof(CommandConsole), "instance");

	private static readonly Color ChargeColor = new Color(0.5f, 0.9f, 1f);

	private static readonly Color LowChargeColor = new Color(0.3f, 0.5f, 0.6f);

	private static readonly Color CooldownColor = new Color(1f, 0.55f, 0.15f);

	private static BootsController instance;

	private ENT_Player trackedPlayer;

	private float energy;

	private float cooldown;

	private bool carrying;

	private bool active;

	private float nextScan;

	private bool inFall;

	private float fallBaseEnergy;

	private float fallOffset;

	private Item lastHeldBoots;

	private float cooldownRate = 1f;

	private float displayCooldownRate = 1f;

	private Object registeredConsole;

	private GUIStyle labelStyle;

	private void Awake()
	{
		instance = this;
	}

	public static bool IsEnabled(Item item)
	{
		return item.GetFirstDataStringByType("resonance-enabled", false) != "0";
	}

	public static void Toggle(Item item)
	{
		bool flag = !IsEnabled(item);
		item.SetFirstDataStringsofType("resonance-enabled", flag ? "1" : "0");
		if ((Object)(object)instance != (Object)null)
		{
			instance.OnToggled(flag);
		}
	}

	public static string StatusLine()
	{
		if ((Object)(object)instance == (Object)null || !instance.carrying)
		{
			return "No boots in your inventory.";
		}
		if (!instance.active)
		{
			return "Boots switched off.";
		}
		if (instance.cooldown > 0f)
		{
			float num = Mathf.Max(instance.cooldownRate, 0.01f);
			return $"Recharging: {instance.cooldown / num:0.0}s left (x{num:0.0})";
		}
		float num2 = Mathf.Clamp01(instance.energy / Mathf.Max(Plugin.MaxStoredEnergy.Value, 0.0001f));
		string arg = ((instance.energy >= Plugin.MinEnergyToBlast.Value) ? "ready" : "below firing charge");
		return $"Charge: {num2 * 100f:0}% ({instance.energy:0.0} m) - {arg}";
	}

	public static void ClearCooldown()
	{
		if ((Object)(object)instance != (Object)null)
		{
			instance.cooldown = 0f;
		}
	}

	public static void FillCharge()
	{
		if ((Object)(object)instance != (Object)null)
		{
			instance.energy = Plugin.MaxStoredEnergy.Value;
			instance.cooldown = 0f;
		}
	}

	private void OnToggled(bool enabled)
	{
		nextScan = 0f;
		ENT_Player playerObject = ENT_Player.playerObject;
		if ((Object)(object)playerObject != (Object)null)
		{
			PlaySound(playerObject, "perk", "doublejump-recharge", enabled ? 1f : 0.4f);
			if ((Object)(object)playerObject.camRoot != (Object)null)
			{
				playerObject.camRoot.ShakeCamera(0.02f);
			}
		}
		ShowStatus(enabled);
	}

	private static void ShowStatus(bool enabled)
	{
		if ((Object)(object)CL_UIManager.instance != (Object)null)
		{
			CL_UIManager.instance.SetDescription(enabled ? "<color=#7FE7FF>Resonance Boots: ON</color>" : "<color=grey>Resonance Boots: OFF</color>");
		}
	}

	private void Update()
	{
		ItemRegistry.Tick();
		RegisterConsoleCommand();
		ENT_Player playerObject = ENT_Player.playerObject;
		if ((Object)(object)playerObject != (Object)(object)trackedPlayer)
		{
			trackedPlayer = playerObject;
			energy = 0f;
			cooldown = 0f;
			inFall = false;
			carrying = false;
			active = false;
			lastHeldBoots = null;
			ChargeAudio.Stop();
		}
		if ((Object)(object)playerObject == (Object)null || (Object)(object)Inventory.instance == (Object)null)
		{
			ChargeAudio.Stop();
			return;
		}
		if (Time.unscaledTime >= nextScan)
		{
			nextScan = Time.unscaledTime + 0.2f;
			ScanInventory();
		}
		UpdateHeldStatus(playerObject);
		cooldown = Mathf.Min(cooldown, Plugin.Cooldown.Value);
		if (cooldown > 0f)
		{
			cooldownRate = CooldownRate(playerObject);
			displayCooldownRate = Mathf.Lerp(displayCooldownRate, cooldownRate, Mathf.Clamp01(Time.deltaTime * 6f));
			cooldown -= Time.deltaTime * cooldownRate;
			if (cooldown <= 0f)
			{
				cooldown = 0f;
				displayCooldownRate = 1f;
				if (active)
				{
					ChargeAudio.OnReady(playerObject);
				}
			}
		}
		bool charging = false;
		if (!active || ((GameEntity)playerObject).dead)
		{
			energy = 0f;
			inFall = false;
		}
		else if (cooldown > 0f)
		{
			inFall = false;
		}
		else
		{
			charging = StoreFallEnergy(playerObject);
			if (energy >= Plugin.MinEnergyToBlast.Value && energy > 0f && BlastPressed() && CanBlast(playerObject))
			{
				Blast(playerObject);
				charging = false;
			}
		}
		ChargeAudio.Tick(playerObject, active && !((GameEntity)playerObject).dead, energy, cooldown > 0f, charging);
	}

	private void ScanInventory()
	{
		bool flag = false;
		carrying = false;
		try
		{
			foreach (Item item in Inventory.instance.GetItems(true, true, true))
			{
				if (ItemRegistry.IsBoots(item))
				{
					carrying = true;
					flag |= IsEnabled(item);
				}
			}
		}
		catch (Exception)
		{
		}
		active = carrying && flag;
	}

	private void UpdateHeldStatus(ENT_Player player)
	{
		Item val = null;
		Hand[] hands = player.hands;
		foreach (Hand val2 in hands)
		{
			HandItem val3 = ((val2 != null) ? val2.GetHandItem() : null);
			if ((Object)(object)val3 != (Object)null && ItemRegistry.IsBoots(val3.item))
			{
				val = val3.item;
				break;
			}
		}
		if (val != null && val != lastHeldBoots)
		{
			ShowStatus(IsEnabled(val));
		}
		lastHeldBoots = val;
	}

	private bool StoreFallEnergy(ENT_Player player)
	{
		float currentFallDistance = player.GetCurrentFallDistance();
		if (currentFallDistance > 0f)
		{
			if (!inFall)
			{
				inFall = true;
				fallBaseEnergy = energy;
				fallOffset = currentFallDistance;
			}
			float num = currentFallDistance - fallOffset;
			if (num >= Plugin.MinFallToStore.Value)
			{
				float num2 = energy;
				energy = Mathf.Min(Plugin.MaxStoredEnergy.Value, Mathf.Max(energy, fallBaseEnergy + num));
				return energy > num2 + 0.0001f;
			}
			return false;
		}
		inFall = false;
		if (player.IsGrounded(false) || player.IsHanging())
		{
			energy = Mathf.Max(0f, energy - Plugin.IdleDrainPerSecond.Value * Time.deltaTime);
		}
		return false;
	}

	private static float CooldownRate(ENT_Player player)
	{
		float num = Mathf.Max(0f, 0f - CorrectedVelocity.Invoke(player).y);
		return Mathf.Clamp(1f + num * Plugin.CooldownFallBonus.Value, 1f, Plugin.CooldownMaxRate.Value);
	}

	private static bool BlastPressed()
	{
		//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_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		KeyCode value = Plugin.BlastKey.Value;
		if ((int)value != 0)
		{
			return Input.GetKeyDown(value);
		}
		ButtonInput button = InputManager.GetButton("Jump");
		if (button != null)
		{
			return button.Down;
		}
		return false;
	}

	private static bool CanBlast(ENT_Player player)
	{
		CL_GameManager gMan = CL_GameManager.gMan;
		if ((Object)(object)gMan == (Object)null || gMan.isPaused || gMan.lockPlayer || gMan.lockPlayerInput || gMan.freecam)
		{
			return false;
		}
		if (((GameEntity)player).dead || player.noclip || player.IsFlying() || player.IsMoveLocked() || IsSwimming.Invoke(player) || CutsceneMode.Invoke(player))
		{
			return false;
		}
		if (Inventory.IsShowingInventory() || player.IsHanging() || player.IsGrounded(true))
		{
			return false;
		}
		return player.GetTimeSinceGrounded() > 0.2f;
	}

	private void Blast(ENT_Player player)
	{
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: 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_00fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_00ec: Unknown result type (might be due to invalid IL or missing references)
		float num = Mathf.InverseLerp(Plugin.MinEnergyToBlast.Value, Plugin.MaxStoredEnergy.Value, energy);
		float num2 = Mathf.Abs(player.jumpHeight * player.gravity);
		float num3 = num2 * Mathf.Lerp(Plugin.MinBlastStrength.Value, Plugin.MaxBlastStrength.Value, num);
		ref Vector3 reference = ref Vel.Invoke(player);
		if (reference.y < 0f)
		{
			reference.y = 0f;
		}
		reference.y += num3;
		Vector3 val = (((Object)(object)player.cam != (Object)null) ? ((Component)player.cam).transform.forward : ((Component)player).transform.forward);
		val.y = 0f;
		if (((Vector3)(ref val)).sqrMagnitude > 0.001f)
		{
			reference += ((Vector3)(ref val)).normalized * (num2 * Plugin.ForwardCarry.Value * num);
		}
		LastVel.Invoke(player) = reference;
		IsGroundedField.Invoke(player) = false;
		ForceAirbornTime.Invoke(player) = 0.1f;
		HasJumped.Invoke(player) = true;
		FallStartHeight.Invoke(player) = CL_GameManager.gMan.GetPlayerCorrectedHeight();
		Falling.Invoke(player) = false;
		CurFallDistance.Invoke(player) = 0f;
		Plugin.Log.LogInfo((object)$"Blast: energy {energy:0.0} m, charge {num:P0}, upward {num3:0.00} ({num3 / Mathf.Max(num2, 0.0001f):0.00}x jump).");
		energy = 0f;
		inFall = false;
		cooldown = Plugin.Cooldown.Value;
		if ((Object)(object)player.camRoot != (Object)null)
		{
			player.camRoot.ShakeCamera(0.05f + 0.1f * num);
		}
		if ((Object)(object)player.jumpBoostEffect != (Object)null)
		{
			player.jumpBoostEffect.Play();
		}
		Shockwave.Spawn(player, num);
		ChargeAudio.OnBlast(player);
		PlaySound(player, "perk", "jumpboost", 1f);
		PlaySound(player, "perk", "doublejump", 0.6f + 0.4f * num);
	}

	private static void PlaySound(ENT_Player player, string group, string set, float volume)
	{
		try
		{
			player.clipHandler.GetGroup(group).GetSet(set).Play(volume, (AudioSource)null);
		}
		catch (Exception)
		{
		}
	}

	private void RegisterConsoleCommand()
	{
		Object val = (Object)((ConsoleInstance != null) ? /*isinst with value type is only supported in some contexts*/: null);
		if (!(val == (Object)null) && !(val == registeredConsole))
		{
			registeredConsole = val;
			CommandConsole.AddCommand("resonanceboots", (Action<string[]>)ConsoleCommand, true);
		}
	}

	private void ConsoleCommand(string[] args)
	{
		if (Array.IndexOf(args, "charge") >= 0)
		{
			energy = Plugin.MaxStoredEnergy.Value;
			cooldown = 0f;
			CommandConsole.Log("Resonance Boots fully charged.");
		}
		else if ((Object)(object)ItemRegistry.Prefab == (Object)null || (Object)(object)Inventory.instance == (Object)null)
		{
			CommandConsole.LogError("Resonance Boots are not available yet.");
		}
		else
		{
			Inventory.instance.AddItemToInventoryCenter(ItemRegistry.Prefab.itemData.GetClone((Item)null, false));
			CommandConsole.Log("Added Resonance Boots to your inventory.");
		}
	}

	private void OnGUI()
	{
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Expected O, but got Unknown
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_020f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0228: Unknown result type (might be due to invalid IL or missing references)
		//IL_024a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0256: Unknown result type (might be due to invalid IL or missing references)
		//IL_0271: Unknown result type (might be due to invalid IL or missing references)
		//IL_0300: Unknown result type (might be due to invalid IL or missing references)
		//IL_0322: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_019b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0194: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
		if (!Plugin.ShowHud.Value || !carrying || (Object)(object)trackedPlayer == (Object)null || ((GameEntity)trackedPlayer).dead)
		{
			return;
		}
		CL_GameManager gMan = CL_GameManager.gMan;
		if ((Object)(object)gMan == (Object)null || gMan.isPaused)
		{
			return;
		}
		if (labelStyle == null)
		{
			labelStyle = new GUIStyle(GUI.skin.label)
			{
				alignment = (TextAnchor)4,
				fontStyle = (FontStyle)1,
				fontSize = 13
			};
		}
		float num = ((float)Screen.width - 220f) * 0.5f;
		float num2 = (float)Screen.height - 64f;
		float value = Plugin.MaxStoredEnergy.Value;
		float num3;
		Color color;
		string text;
		int num4;
		Color val;
		if (!active)
		{
			num3 = 0f;
			color = Color.grey;
			text = "RESONANCE BOOTS  OFF";
		}
		else
		{
			if (!(cooldown > 0f))
			{
				num3 = energy / value;
				if (energy >= Plugin.MinEnergyToBlast.Value)
				{
					num4 = ((energy > 0f) ? 1 : 0);
					if (num4 != 0)
					{
						val = ChargeColor;
						goto IL_01a0;
					}
				}
				else
				{
					num4 = 0;
				}
				val = LowChargeColor;
				goto IL_01a0;
			}
			num3 = ((Plugin.Cooldown.Value > 0f) ? (1f - cooldown / Plugin.Cooldown.Value) : 1f);
			color = CooldownColor;
			text = ((displayCooldownRate > 1.05f) ? $"RECHARGING  {Mathf.CeilToInt(cooldown)}s  x{displayCooldownRate:0.0}" : $"RECHARGING  {Mathf.CeilToInt(cooldown)}s");
		}
		goto IL_0208;
		IL_01a0:
		color = val;
		string arg = (((int)Plugin.BlastKey.Value == 0) ? "JUMP IN AIR" : ("PRESS " + ((object)Plugin.BlastKey.Value/*cast due to .constrained prefix*/).ToString().ToUpper()));
		text = ((num4 != 0) ? $"RESONANCE  {Mathf.RoundToInt(num3 * 100f)}%  {arg}" : "RESONANCE  FALL TO CHARGE");
		goto IL_0208;
		IL_0208:
		Texture2D whiteTexture = Texture2D.whiteTexture;
		Color color2 = GUI.color;
		GUI.color = new Color(0f, 0f, 0f, 0.6f);
		GUI.DrawTexture(new Rect(num - 2f, num2 - 2f, 224f, 12f), (Texture)(object)whiteTexture);
		GUI.color = color;
		GUI.DrawTexture(new Rect(num, num2, 220f * Mathf.Clamp01(num3), 8f), (Texture)(object)whiteTexture);
		if (active && cooldown <= 0f)
		{
			GUI.color = new Color(1f, 1f, 1f, 0.7f);
			GUI.DrawTexture(new Rect(num + 220f * Mathf.Clamp01(Plugin.MinEnergyToBlast.Value / value) - 1f, num2 - 3f, 2f, 14f), (Texture)(object)whiteTexture);
		}
		GUI.color = new Color(1f, 1f, 1f, 0.9f);
		GUI.Label(new Rect(num - 40f, num2 - 22f, 300f, 20f), text, labelStyle);
		GUI.color = color2;
	}
}
internal static class ChargeAudio
{
	private static readonly float[] BlipPoints = new float[3] { 0.25f, 0.5f, 0.75f };

	private static AudioSource loopSource;

	private static AudioClip loopClip;

	private static AudioClip fullClip;

	private static AudioClip readyClip;

	private static float nextClipSearch;

	private static float currentVolume;

	private static int lastBlip;

	private static bool wasFull;

	public static void Tick(ENT_Player player, bool active, float energy, bool cooldownActive, bool charging)
	{
		if ((Object)(object)player == (Object)null || !Plugin.ChargeAudioEnabled.Value)
		{
			Stop();
			return;
		}
		EnsureClips();
		if (!active || cooldownActive)
		{
			lastBlip = 0;
			wasFull = false;
			FadeOut();
			return;
		}
		float num = Mathf.Max(Plugin.MaxStoredEnergy.Value, 0.0001f);
		float num2 = Mathf.Clamp01(energy / num);
		int num3 = 0;
		float[] blipPoints = BlipPoints;
		foreach (float num4 in blipPoints)
		{
			if (num2 >= num4)
			{
				num3++;
			}
		}
		if (num3 > lastBlip && Plugin.ChargeBlips.Value)
		{
			PlayOneShot(player, readyClip, "perk", "doublejump-recharge", 0.35f, 0.9f + 0.15f * (float)num3);
		}
		lastBlip = num3;
		bool flag = energy >= Plugin.MaxStoredEnergy.Value - 0.01f;
		if (flag && !wasFull)
		{
			PlayOneShot(player, fullClip, "perk", "jumpboost", 0.7f, 1.1f);
		}
		wasFull = flag;
		if (charging && !flag)
		{
			RunLoop(player, num2);
		}
		else
		{
			FadeOut();
		}
	}

	public static void OnBlast(ENT_Player player)
	{
		StopLoop();
		PlayOneShot(player, fullClip, "perk", "jumpboost", 0.9f, 0.8f);
	}

	public static void OnReady(ENT_Player player)
	{
		PlayOneShot(player, readyClip, "perk", "doublejump-recharge", 0.8f, 1.15f);
	}

	public static void Stop()
	{
		currentVolume = 0f;
		lastBlip = 0;
		wasFull = false;
		StopLoop();
	}

	private static void RunLoop(ENT_Player player, float fraction)
	{
		if ((Object)(object)loopClip == (Object)null)
		{
			return;
		}
		EnsureSource(player);
		if (!((Object)(object)loopSource == (Object)null))
		{
			if ((Object)(object)loopSource.clip != (Object)(object)loopClip)
			{
				loopSource.clip = loopClip;
			}
			if (!loopSource.isPlaying)
			{
				loopSource.Play();
			}
			loopSource.pitch = Mathf.Lerp(0.7f, 1.7f, fraction);
			float num = Plugin.ChargeVolume.Value * Mathf.Lerp(0.3f, 1f, fraction);
			currentVolume = Mathf.MoveTowards(currentVolume, num, Time.deltaTime * 4f);
			loopSource.volume = currentVolume;
		}
	}

	private static void FadeOut()
	{
		if (!((Object)(object)loopSource == (Object)null) && loopSource.isPlaying)
		{
			currentVolume = Mathf.MoveTowards(currentVolume, 0f, Time.deltaTime * 3f);
			loopSource.volume = currentVolume;
			if (currentVolume <= 0.001f)
			{
				StopLoop();
			}
		}
	}

	private static void StopLoop()
	{
		if ((Object)(object)loopSource != (Object)null && loopSource.isPlaying)
		{
			loopSource.Stop();
		}
		currentVolume = 0f;
	}

	private static void EnsureSource(ENT_Player player)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Expected O, but got Unknown
		if (!((Object)(object)loopSource != (Object)null))
		{
			GameObject val = new GameObject("ResonanceBootsChargeAudio")
			{
				hideFlags = (HideFlags)61
			};
			Object.DontDestroyOnLoad((Object)val);
			loopSource = val.AddComponent<AudioSource>();
			loopSource.loop = true;
			loopSource.playOnAwake = false;
			loopSource.spatialBlend = 0f;
			loopSource.volume = 0f;
			AudioSource componentInChildren = ((Component)player).GetComponentInChildren<AudioSource>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				loopSource.outputAudioMixerGroup = componentInChildren.outputAudioMixerGroup;
			}
		}
	}

	private static void EnsureClips()
	{
		if (!(Time.unscaledTime < nextClipSearch) && (!((Object)(object)loopClip != (Object)null) || !((Object)(object)fullClip != (Object)null) || !((Object)(object)readyClip != (Object)null)))
		{
			nextClipSearch = Time.unscaledTime + 5f;
			AudioClip[] clips = Resources.FindObjectsOfTypeAll<AudioClip>();
			loopClip = (((Object)(object)loopClip != (Object)null) ? loopClip : Find(clips, Plugin.ChargeLoopClip.Value));
			fullClip = (((Object)(object)fullClip != (Object)null) ? fullClip : Find(clips, Plugin.FullChargeClip.Value));
			readyClip = (((Object)(object)readyClip != (Object)null) ? readyClip : Find(clips, Plugin.ReadyClip.Value));
		}
	}

	private static AudioClip Find(AudioClip[] clips, string name)
	{
		if (string.IsNullOrEmpty(name))
		{
			return null;
		}
		AudioClip[] array = clips;
		foreach (AudioClip val in array)
		{
			if (string.Equals(((Object)val).name, name, StringComparison.OrdinalIgnoreCase))
			{
				return val;
			}
		}
		array = clips;
		foreach (AudioClip val2 in array)
		{
			if (((Object)val2).name.IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return val2;
			}
		}
		return null;
	}

	private static void PlayOneShot(ENT_Player player, AudioClip clip, string group, string set, float volume, float pitch)
	{
		if ((Object)(object)clip != (Object)null)
		{
			Transform val = (((Object)(object)player.cam != (Object)null) ? ((Component)player.cam).transform : ((Component)player).transform);
			AudioManager.PlaySound(clip, val, volume * Plugin.ChargeVolume.Value, pitch, 0f, false, 1f, (AudioMixerGroup)null, "");
			return;
		}
		try
		{
			player.clipHandler.GetGroup(group).GetSet(set).Play(volume, (AudioSource)null);
		}
		catch (Exception)
		{
		}
	}
}
internal static class ItemRegistry
{
	public const string PrefabName = "Item_Artifact_ResonanceBoots";

	public const string DisplayName = "Resonance Boots";

	public const string Description = "<color=#7FE7FF>Artifact: Resonance Boots.</color> Stores kinetic energy from falls. Jump in mid-air to release it as a repulsion blast. Click while held to switch them on or off.";

	private const string DatabaseId = "resonanceboots";

	private static readonly string[] SourcePrefabs = new string[5] { "Item_Trinket_ClimbingShoes", "Item_Trinket_Climbingshoe", "Item_Artifact_Watch", "Item_Artifact_Timepiece", "Item_Beans" };

	private static readonly FieldInfo[] HandFields = typeof(HandItem).GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Concat(typeof(Hand_Base).GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)).ToArray();

	private static WKAssetDatabase database;

	private static float nextCheck;

	private static int failedAttempts;

	public static Item_Object Prefab { get; private set; }

	public static bool IsBoots(Item item)
	{
		if (item != null)
		{
			return item.prefabName == "Item_Artifact_ResonanceBoots";
		}
		return false;
	}

	public static void Tick()
	{
		if (Time.unscaledTime < nextCheck || (Object)(object)CL_AssetManager.baseDatabase == (Object)null || failedAttempts > 30)
		{
			return;
		}
		nextCheck = Time.unscaledTime + 2f;
		try
		{
			CL_AssetManager.InitializeAssetManager();
			if ((Object)(object)Prefab == (Object)null)
			{
				Build();
			}
			else if ((Object)(object)CL_AssetManager.GetItemObjectPrefab("Item_Artifact_ResonanceBoots", "") == (Object)null)
			{
				CL_AssetManager.AddNewDatabase("resonanceboots", database);
			}
		}
		catch (Exception ex)
		{
			failedAttempts++;
			Plugin.Log.LogError((object)("Failed to register Resonance Boots: " + ex));
		}
	}

	private static void Build()
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Expected O, but got Unknown
		Item_Object val = FindSource();
		if ((Object)(object)val == (Object)null)
		{
			if (++failedAttempts == 15)
			{
				Plugin.Log.LogError((object)"Could not find a base item to build the Resonance Boots from.");
			}
			return;
		}
		GameObject val2 = new GameObject("ResonanceBoots_Templates");
		val2.SetActive(false);
		((Object)val2).hideFlags = (HideFlags)61;
		Object.DontDestroyOnLoad((Object)(object)val2);
		HandItem hand = BuildHandItem(val.itemData.handItemAsset, val2.transform);
		GameObject val3 = Object.Instantiate<GameObject>(((Component)val).gameObject, val2.transform);
		((Object)val3).name = "Item_Artifact_ResonanceBoots";
		Item_Object component = val3.GetComponent<Item_Object>();
		SetupItemData(component, hand);
		CL_Prop component2 = val3.GetComponent<CL_Prop>();
		if ((Object)(object)component2 != (Object)null)
		{
			Traverse val4 = Traverse.Create((object)component2).Field("entityPrefabID");
			if (val4.FieldExists())
			{
				val4.SetValue((object)"Item_Artifact_ResonanceBoots");
			}
		}
		TintWorldModel(val3);
		database = ScriptableObject.CreateInstance<WKAssetDatabase>();
		((Object)database).name = "resonanceboots";
		database.id = "resonanceboots";
		((Object)database).hideFlags = (HideFlags)61;
		database.itemPrefabs.Add(val3);
		CL_AssetManager.AddNewDatabase("resonanceboots", database);
		Prefab = component;
		Plugin.Log.LogInfo((object)("Registered Item_Artifact_ResonanceBoots using the model from " + ((Object)val).name + "."));
	}

	private static Item_Object FindSource()
	{
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		string[] sourcePrefabs = SourcePrefabs;
		for (int i = 0; i < sourcePrefabs.Length; i++)
		{
			Item_Object itemObjectPrefab = CL_AssetManager.GetItemObjectPrefab(sourcePrefabs[i], "");
			if (IsUsableSource(itemObjectPrefab))
			{
				return itemObjectPrefab;
			}
		}
		Item_Object[] array = Resources.FindObjectsOfTypeAll<Item_Object>();
		sourcePrefabs = SourcePrefabs;
		foreach (string text in sourcePrefabs)
		{
			Item_Object[] array2 = array;
			foreach (Item_Object val in array2)
			{
				if (((Object)val).name == text)
				{
					Scene scene = ((Component)val).gameObject.scene;
					if (!((Scene)(ref scene)).IsValid() && IsUsableSource(val))
					{
						return val;
					}
				}
			}
		}
		return null;
	}

	private static bool IsUsableSource(Item_Object item)
	{
		if ((Object)(object)item != (Object)null && ((object)item).GetType() == typeof(Item_Object) && item.itemData != null)
		{
			return (Object)(object)item.itemData.handItemAsset != (Object)null;
		}
		return false;
	}

	private static HandItem BuildHandItem(HandItem sourceHand, Transform parent)
	{
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Expected O, but got Unknown
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Expected O, but got Unknown
		GameObject val = Object.Instantiate<GameObject>(((Component)sourceHand).gameObject, parent);
		((Object)val).name = "Item_Hands_ResonanceBoots";
		HandItem component = val.GetComponent<HandItem>();
		HandItem val2 = component;
		if (((object)component).GetType() != typeof(HandItem))
		{
			val2 = val.AddComponent<HandItem>();
			FieldInfo[] handFields = HandFields;
			foreach (FieldInfo fieldInfo in handFields)
			{
				fieldInfo.SetValue(val2, fieldInfo.GetValue(component));
			}
			Object.DestroyImmediate((Object)(object)component);
		}
		val2.itemUseEvent = new UnityEvent();
		val2.firstGrabEvent = new UnityEvent();
		val2.firstGrabFlag = "";
		val2.simpleUseModules = new List<SimpleModule>();
		val2.useStats = new List<string>();
		val2.canUseWhileHanging = true;
		if (val2.interactionModules == null)
		{
			val2.interactionModules = new List<Item_InteractionModule>();
		}
		if (val2.itemCosmetics == null)
		{
			val2.itemCosmetics = new List<Cosmetic_Item>();
		}
		return val2;
	}

	private static void SetupItemData(Item_Object boots, HandItem hand)
	{
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		Item itemData = boots.itemData;
		itemData.itemName = "Resonance Boots";
		itemData.prefabName = "Item_Artifact_ResonanceBoots";
		itemData.itemTag = "artifact";
		itemData.itemTags = new List<string> { "artifact", "resonanceboots" };
		itemData.itemAsset = boots;
		itemData.handItemAsset = hand;
		itemData.data = new List<string> { "resonance-enabled:1" };
		itemData.dataModules = new List<Item_Data>();
		itemData.dataModuleSaves = new List<DataModuleSave>();
		itemData.executionModules = new List<ItemExecutionModule>();
		itemData.useFlags = false;
		itemData.flagOnPickup = "";
		itemData.flagOnDrop = "";
		itemData.pickupStat = "";
		itemData.unlockType = (UnlockType)0;
		itemData.progressionUnlockID = "";
		itemData.allowCosmetics = false;
		itemData.used = false;
		itemData.itemGUID = "";
		itemData.hasBeenDestroyed = false;
		itemData.pocketable = true;
		itemData.pouchable = true;
	}

	private static void TintWorldModel(GameObject itemObject)
	{
		//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_000b: 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_005f: Expected O, but got Unknown
		//IL_0066: 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)
		Color value = Plugin.TintColor.Value;
		if (value.a <= 0f)
		{
			return;
		}
		Renderer[] componentsInChildren = itemObject.GetComponentsInChildren<Renderer>(true);
		foreach (Renderer val in componentsInChildren)
		{
			if (!(val is MeshRenderer) && !(val is SkinnedMeshRenderer))
			{
				continue;
			}
			Material[] sharedMaterials = val.sharedMaterials;
			for (int j = 0; j < sharedMaterials.Length; j++)
			{
				if (!((Object)(object)sharedMaterials[j] == (Object)null))
				{
					Material val2 = new Material(sharedMaterials[j]);
					TintProperty(val2, "_Color", value);
					TintProperty(val2, "_BaseColor", value);
					sharedMaterials[j] = val2;
				}
			}
			val.sharedMaterials = sharedMaterials;
		}
	}

	private static void TintProperty(Material material, string property, Color tint)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: 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)
		if (material.HasProperty(property))
		{
			Color color = material.GetColor(property);
			Color val = Color.Lerp(color, tint, tint.a);
			val.a = color.a;
			material.SetColor(property, val);
		}
	}
}
internal static class OverlayIntegration
{
	public static void TryRegister()
	{
		try
		{
			WKLibAPI.Create("Resonance Boots", "jackziferz.resonanceboots").AddToModList((ModTab)(object)new BootsModTab());
			Plugin.Log.LogInfo((object)"Added the Resonance Boots tab to the WKLib overlay.");
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("Could not add the WKLib overlay tab: " + ex.Message));
		}
	}
}
internal class BootsModTab : ModTab
{
	public override string DisplayName => "Resonance Boots";

	public override void DrawSubMenu(ImGui gui)
	{
		//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: 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)
		ImText.Text(gui, BootsController.StatusLine().AsSpan(), false, (ImTextOverflow)0);
		ImSeparator.Separator(gui, "Cooldown".AsSpan());
		Slider(gui, "Cooldown", "s", Plugin.Cooldown, 0f, 60f);
		Slider(gui, "Falling bonus", "per m/s", Plugin.CooldownFallBonus, 0f, 0.3f);
		Slider(gui, "Fastest rate", "x", Plugin.CooldownMaxRate, 1f, 10f);
		ImSeparator.Separator(gui, "Blast".AsSpan());
		Slider(gui, "Charge cap", "m", Plugin.MaxStoredEnergy, 5f, 100f);
		Slider(gui, "Minimum strength", "x jump", Plugin.MinBlastStrength, 0f, 8f);
		Slider(gui, "Full-charge strength", "x jump", Plugin.MaxBlastStrength, 0f, 8f);
		if (ImButton.Button(gui, "Clear cooldown".AsSpan(), default(ImSize), (ImButtonFlag)0))
		{
			BootsController.ClearCooldown();
		}
		if (ImButton.Button(gui, "Fill charge".AsSpan(), default(ImSize), (ImButtonFlag)0))
		{
			BootsController.FillCharge();
		}
		ImSeparator.Separator(gui, "All settings".AsSpan());
		string text = null;
		foreach (ConfigEntryBase item in AllEntries())
		{
			if (item.Definition.Section != text)
			{
				text = item.Definition.Section;
				ImSeparator.Separator(gui, text.AsSpan());
			}
			UIUtility.DrawConfigEntry(gui, item);
		}
	}

	private static IEnumerable<ConfigEntryBase> AllEntries()
	{
		if (Plugin.ConfigFile == null)
		{
			return Enumerable.Empty<ConfigEntryBase>();
		}
		return from pair in ((IEnumerable<KeyValuePair<ConfigDefinition, ConfigEntryBase>>)Plugin.ConfigFile).OrderBy<KeyValuePair<ConfigDefinition, ConfigEntryBase>, string>((KeyValuePair<ConfigDefinition, ConfigEntryBase> pair) => pair.Key.Section, StringComparer.OrdinalIgnoreCase)
			select pair.Value;
	}

	private static void Slider(ImGui gui, string label, string unit, ConfigEntry<float> entry, float min, float max)
	{
		//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)
		float value = entry.Value;
		ImText.Text(gui, $"{label}: {value:0.##} {unit}".AsSpan(), false, (ImTextOverflow)0);
		if (ImSlider.Slider(gui, ref value, min, max, default(ImSize), 0f, (ImSliderFlag)0))
		{
			entry.Value = value;
		}
	}
}
internal static class Patches
{
	private static readonly MethodInfo CloneMethod = AccessTools.Method(typeof(object), "MemberwiseClone", (Type[])null, (Type[])null);

	private static readonly HashSet<int> patchedTables = new HashSet<int>();

	[HarmonyPatch(typeof(Item), "Use")]
	[HarmonyPrefix]
	private static bool ItemUsePrefix(Item __instance)
	{
		if (!ItemRegistry.IsBoots(__instance))
		{
			return true;
		}
		HandItem handItem = __instance.GetHandItem();
		if ((!((Object)(object)handItem != (Object)null) || !handItem.IsCurrentlyInteracting()) && !__instance.HasTag("unpurchased"))
		{
			BootsController.Toggle(__instance);
		}
		return false;
	}

	[HarmonyPatch(typeof(Item_Object), "OnHover")]
	[HarmonyPostfix]
	private static void OnHoverPostfix(Item_Object __instance)
	{
		if (ItemRegistry.IsBoots(__instance.itemData) && (Object)(object)CL_UIManager.instance != (Object)null)
		{
			CL_UIManager.instance.SetDescription("<color=#7FE7FF>Artifact: Resonance Boots.</color> Stores kinetic energy from falls. Jump in mid-air to release it as a repulsion blast. Click while held to switch them on or off.");
		}
	}

	[HarmonyPatch(typeof(ENV_ArtifactDevice), "Start")]
	[HarmonyPrefix]
	private static void ArtifactDevicePrefix(ENV_ArtifactDevice __instance)
	{
		Item_Object prefab = ItemRegistry.Prefab;
		if (!((Object)(object)prefab == (Object)null) && __instance.artifacts != null && !__instance.artifacts.Contains(prefab) && Random.value < Plugin.ArtifactDeviceChance.Value)
		{
			__instance.artifacts.Add(prefab);
		}
	}

	[HarmonyPatch(typeof(SpawnTable), "GetRandomSpawnObject")]
	[HarmonyPrefix]
	private static void SpawnTablePrefix(SpawnTable __instance)
	{
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Expected O, but got Unknown
		//IL_008a: 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_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e1: Expected O, but got Unknown
		if (!((Object)(object)ItemRegistry.Prefab == (Object)null) && !(Plugin.SpawnTableWeight.Value <= 0f) && __instance.spawnList != null && patchedTables.Add(((Object)__instance).GetInstanceID()))
		{
			SpawnTableAsset val = __instance.spawnList.Find(IsArtifactEntry);
			if (val != null)
			{
				SpawnSettings val2 = (SpawnSettings)CloneMethod.Invoke(val.spawnSettings, null);
				val2.chanceMultiplier *= Plugin.SpawnTableWeight.Value;
				__instance.spawnList.Add(new SpawnTableAsset
				{
					name = "Resonance Boots",
					tags = ((val.tags != null) ? new List<string>(val.tags) : new List<string>()),
					prefabs = new List<GameObject> { ((Component)ItemRegistry.Prefab).gameObject },
					spawnSettings = val2
				});
				Plugin.Log.LogInfo((object)("Added Resonance Boots to spawn table '" + ((Object)__instance).name + "' (odds copied from '" + val.name + "')."));
			}
		}
	}

	private static bool IsArtifactEntry(SpawnTableAsset entry)
	{
		if (entry != null && entry.spawnSettings != null && entry.prefabs != null)
		{
			return entry.prefabs.Exists((GameObject p) => (Object)(object)p != (Object)null && ((Object)p).name.StartsWith("Item_Artifact_") && ((Object)p).name != "Item_Artifact_ResonanceBoots");
		}
		return false;
	}
}
[BepInPlugin("jackziferz.resonanceboots", "Resonance Boots", "1.2.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
	public const string PluginGuid = "jackziferz.resonanceboots";

	public const string PluginName = "Resonance Boots";

	public const string PluginVersion = "1.2.0";

	public const string WKLibGuid = "com.monksilly.WKLib";

	internal static ManualLogSource Log;

	internal static ConfigFile ConfigFile;

	internal static ConfigEntry<float> MaxStoredEnergy;

	internal static ConfigEntry<float> MinFallToStore;

	internal static ConfigEntry<float> MinEnergyToBlast;

	internal static ConfigEntry<float> IdleDrainPerSecond;

	internal static ConfigEntry<float> MinBlastStrength;

	internal static ConfigEntry<float> MaxBlastStrength;

	internal static ConfigEntry<float> ForwardCarry;

	internal static ConfigEntry<float> Cooldown;

	internal static ConfigEntry<float> CooldownFallBonus;

	internal static ConfigEntry<float> CooldownMaxRate;

	internal static ConfigEntry<KeyCode> BlastKey;

	internal static ConfigEntry<float> ArtifactDeviceChance;

	internal static ConfigEntry<float> SpawnTableWeight;

	internal static ConfigEntry<bool> ChargeAudioEnabled;

	internal static ConfigEntry<float> ChargeVolume;

	internal static ConfigEntry<bool> ChargeBlips;

	internal static ConfigEntry<string> ChargeLoopClip;

	internal static ConfigEntry<string> FullChargeClip;

	internal static ConfigEntry<string> ReadyClip;

	internal static ConfigEntry<bool> ShockwaveEnabled;

	internal static ConfigEntry<float> ShockwaveMinRadius;

	internal static ConfigEntry<float> ShockwaveMaxRadius;

	internal static ConfigEntry<float> ShockwaveDuration;

	internal static ConfigEntry<Color> ShockwaveColor;

	internal static ConfigEntry<string> ShockwavePrefabName;

	internal static ConfigEntry<bool> ShowHud;

	internal static ConfigEntry<Color> TintColor;

	private void Awake()
	{
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Expected O, but got Unknown
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Expected O, but got Unknown
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Expected O, but got Unknown
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0105: Expected O, but got Unknown
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		//IL_0142: Expected O, but got Unknown
		//IL_0175: Unknown result type (might be due to invalid IL or missing references)
		//IL_017f: Expected O, but got Unknown
		//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bc: Expected O, but got Unknown
		//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f9: Expected O, but got Unknown
		//IL_022c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0236: Expected O, but got Unknown
		//IL_0269: Unknown result type (might be due to invalid IL or missing references)
		//IL_0273: Expected O, but got Unknown
		//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d0: Expected O, but got Unknown
		//IL_0303: Unknown result type (might be due to invalid IL or missing references)
		//IL_030d: Expected O, but got Unknown
		//IL_0360: Unknown result type (might be due to invalid IL or missing references)
		//IL_036a: Expected O, but got Unknown
		//IL_0449: Unknown result type (might be due to invalid IL or missing references)
		//IL_0453: Expected O, but got Unknown
		//IL_0486: Unknown result type (might be due to invalid IL or missing references)
		//IL_0490: Expected O, but got Unknown
		//IL_04c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_04cd: Expected O, but got Unknown
		//IL_04f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0572: Unknown result type (might be due to invalid IL or missing references)
		//IL_05a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_05a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_05b3: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		ConfigFile = ((BaseUnityPlugin)this).Config;
		MaxStoredEnergy = ((BaseUnityPlugin)this).Config.Bind<float>("Energy", "MaxStoredEnergy", 40f, new ConfigDescription("Most energy the boots can hold, in meters fallen. Falls start hurting at 50 m, so a full charge is ready before then.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 200f), Array.Empty<object>()));
		MinFallToStore = ((BaseUnityPlugin)this).Config.Bind<float>("Energy", "MinFallToStore", 4f, new ConfigDescription("A fall must be at least this many meters before it charges the boots. Keeps ordinary hops from charging them.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>()));
		MinEnergyToBlast = ((BaseUnityPlugin)this).Config.Bind<float>("Energy", "MinEnergyToBlast", 8f, new ConfigDescription("Energy (meters fallen) needed before a blast can be fired.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), Array.Empty<object>()));
		IdleDrainPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Energy", "IdleDrainPerSecond", 1f, new ConfigDescription("Energy lost per second while standing or hanging. 0 keeps stored energy until it is used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>()));
		MinBlastStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Blast", "MinBlastStrength", 1.75f, new ConfigDescription("Upward speed of a minimum-charge blast, as a multiple of your normal jump speed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>()));
		MaxBlastStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Blast", "MaxBlastStrength", 3.25f, new ConfigDescription("Upward speed of a full-charge blast, as a multiple of your normal jump speed. Height grows with the square of this.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>()));
		ForwardCarry = ((BaseUnityPlugin)this).Config.Bind<float>("Blast", "ForwardCarry", 0.5f, new ConfigDescription("Horizontal push toward where you are looking at full charge, as a multiple of your normal jump speed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
		Cooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Blast", "Cooldown", 25f, new ConfigDescription("Seconds after a blast before the boots store energy or fire again.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f), Array.Empty<object>()));
		CooldownFallBonus = ((BaseUnityPlugin)this).Config.Bind<float>("Blast", "CooldownFallBonus", 0.06f, new ConfigDescription("Extra cooldown speed per meter/second you are falling. At 0.06, falling at 25 m/s recharges the boots 2.5x as fast. 0 disables it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		CooldownMaxRate = ((BaseUnityPlugin)this).Config.Bind<float>("Blast", "CooldownMaxRate", 4f, new ConfigDescription("Fastest the cooldown may run, as a multiple of normal.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f), Array.Empty<object>()));
		BlastKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Blast", "BlastKey", (KeyCode)0, "Key that fires the blast. None = press your Jump binding while airborne.");
		ArtifactDeviceChance = ((BaseUnityPlugin)this).Config.Bind<float>("Spawning", "ArtifactDeviceChance", 0.5f, new ConfigDescription("Chance that an artifact device includes the boots among the artifacts it can offer.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		SpawnTableWeight = ((BaseUnityPlugin)this).Config.Bind<float>("Spawning", "SpawnTableWeight", 1f, new ConfigDescription("Spawn weight in loot tables that already hold artifacts, relative to the artifact it is copied from. 0 disables loot spawns.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
		ChargeAudioEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "ChargeAudioEnabled", true, "Tell the charge by ear: a loop that rises in pitch as the boots take in a fall, a blip at each quarter, and a chime when they fill.");
		ChargeVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "ChargeVolume", 0.7f, new ConfigDescription("Volume of the boots' own sounds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
		ChargeBlips = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "ChargeBlips", true, "Play a blip each time the charge passes a quarter, a half and three quarters.");
		ChargeLoopClip = ((BaseUnityPlugin)this).Config.Bind<string>("Audio", "ChargeLoopClip", "item_cryogun_charge_loop", "Game sound used for the charging loop. Any loaded clip name works; leave empty for none.");
		FullChargeClip = ((BaseUnityPlugin)this).Config.Bind<string>("Audio", "FullChargeClip", "item_cryogun_chargedshot", "Game sound played when the boots reach a full charge, and again when they fire.");
		ReadyClip = ((BaseUnityPlugin)this).Config.Bind<string>("Audio", "ReadyClip", "double_jump_recharge", "Game sound for the charge blips and for coming off cooldown.");
		ShockwaveEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Shockwave", "ShockwaveEnabled", true, "Burst a ring outward when the boots fire.");
		ShockwaveMinRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Shockwave", "ShockwaveMinRadius", 1.5f, new ConfigDescription("Ring radius (meters) for a minimum-charge blast.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 50f), Array.Empty<object>()));
		ShockwaveMaxRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Shockwave", "ShockwaveMaxRadius", 6f, new ConfigDescription("Ring radius (meters) for a full-charge blast.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 50f), Array.Empty<object>()));
		ShockwaveDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Shockwave", "ShockwaveDuration", 0.45f, new ConfigDescription("Seconds the ring takes to expand and fade.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 5f), Array.Empty<object>()));
		ShockwaveColor = ((BaseUnityPlugin)this).Config.Bind<Color>("Shockwave", "ShockwaveColor", new Color(0.6f, 0.95f, 1f, 0.85f), "Ring color. Alpha is its starting opacity.");
		ShockwavePrefabName = ((BaseUnityPlugin)this).Config.Bind<string>("Shockwave", "ShockwavePrefabName", "", "Optional: name of a game effect prefab to spawn instead of the built-in ring, for example FX_Shockwave. Only works if that effect is loaded.");
		ShowHud = ((BaseUnityPlugin)this).Config.Bind<bool>("Interface", "ShowHud", true, "Show the on-screen charge / cooldown meter. Turn it off to go by the boots' sounds alone.");
		TintColor = ((BaseUnityPlugin)this).Config.Bind<Color>("Interface", "TintColor", new Color(0.35f, 0.85f, 1f, 0.45f), "Tint applied to the boots' world model. Alpha is the tint strength; 0 keeps the original look.");
		Harmony.CreateAndPatchAll(typeof(Patches), "jackziferz.resonanceboots");
		GameObject val = new GameObject("ResonanceBoots")
		{
			hideFlags = (HideFlags)61
		};
		Object.DontDestroyOnLoad((Object)val);
		val.AddComponent<BootsController>();
		if (Chainloader.PluginInfos.ContainsKey("com.monksilly.WKLib"))
		{
			OverlayIntegration.TryRegister();
		}
		Log.LogInfo((object)"Resonance Boots 1.2.0 loaded.");
	}
}
internal static class Shockwave
{
	private static readonly string[] ShaderCandidates = new string[6] { "Sprites/Default", "Particles/Standard Unlit", "Legacy Shaders/Particles/Alpha Blended Premultiply", "Legacy Shaders/Particles/Alpha Blended", "Unlit/Transparent", "Hidden/Internal-Colored" };

	private static Mesh ringMesh;

	private static Material material;

	private static GameObject prefab;

	private static float nextPrefabSearch;

	public static void Spawn(ENT_Player player, float charge)
	{
		//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_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: 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_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: 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_00e0: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)player == (Object)null) && Plugin.ShockwaveEnabled.Value)
		{
			float radius = Mathf.Lerp(Plugin.ShockwaveMinRadius.Value, Plugin.ShockwaveMaxRadius.Value, Mathf.Clamp01(charge));
			Vector3 position = FeetPosition(player);
			if (!SpawnGamePrefab(position, radius))
			{
				GameObject val = new GameObject("ResonanceShockwave");
				val.transform.position = position;
				val.transform.rotation = Quaternion.Euler(0f, Random.Range(0f, 360f), 0f);
				val.transform.localScale = Vector3.zero;
				val.AddComponent<MeshFilter>().sharedMesh = GetRingMesh();
				MeshRenderer obj = val.AddComponent<MeshRenderer>();
				((Renderer)obj).sharedMaterial = GetMaterial();
				((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
				((Renderer)obj).receiveShadows = false;
				((Renderer)obj).lightProbeUsage = (LightProbeUsage)0;
				val.AddComponent<ShockwaveAnimator>().Initialize(radius, Plugin.ShockwaveDuration.Value, Plugin.ShockwaveColor.Value);
			}
		}
	}

	private static Vector3 FeetPosition(ENT_Player player)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: 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_004c: 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)
		Vector3 val = ((Component)player).transform.position;
		if ((Object)(object)player.cCon != (Object)null)
		{
			val += player.cCon.center - Vector3.up * (player.cCon.height * 0.5f - 0.15f);
		}
		return val;
	}

	private static bool SpawnGamePrefab(Vector3 position, float radius)
	{
		//IL_00bb: 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_00cd: 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_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		string value = Plugin.ShockwavePrefabName.Value;
		if (string.IsNullOrEmpty(value))
		{
			return false;
		}
		if ((Object)(object)prefab == (Object)null && Time.unscaledTime >= nextPrefabSearch)
		{
			nextPrefabSearch = Time.unscaledTime + 5f;
			GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>();
			foreach (GameObject val in array)
			{
				if (((Object)val).name == value)
				{
					Scene scene = val.scene;
					if (!((Scene)(ref scene)).IsValid())
					{
						prefab = val;
						break;
					}
				}
			}
			if ((Object)(object)prefab == (Object)null)
			{
				Plugin.Log.LogWarning((object)("Shockwave prefab '" + value + "' is not loaded; using the built-in ring."));
			}
		}
		if ((Object)(object)prefab == (Object)null)
		{
			return false;
		}
		GameObject obj = Object.Instantiate<GameObject>(prefab, position, Quaternion.identity);
		Transform transform = obj.transform;
		transform.localScale *= radius;
		Object.Destroy((Object)(object)obj, 5f);
		return true;
	}

	private static Material GetMaterial()
	{
		//IL_003c: 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_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Expected O, but got Unknown
		if ((Object)(object)material != (Object)null)
		{
			return material;
		}
		Shader val = null;
		string[] shaderCandidates = ShaderCandidates;
		for (int i = 0; i < shaderCandidates.Length; i++)
		{
			val = Shader.Find(shaderCandidates[i]);
			if ((Object)(object)val != (Object)null)
			{
				break;
			}
		}
		material = new Material(val)
		{
			hideFlags = (HideFlags)61,
			renderQueue = 3000
		};
		if (material.HasProperty("_ZWrite"))
		{
			material.SetInt("_ZWrite", 0);
		}
		if (material.HasProperty("_Cull"))
		{
			material.SetInt("_Cull", 0);
		}
		return material;
	}

	private static Mesh GetRingMesh()
	{
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: 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_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0131: Unknown result type (might be due to invalid IL or missing references)
		//IL_013c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0149: Expected O, but got Unknown
		//IL_017b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0180: Unknown result type (might be due to invalid IL or missing references)
		//IL_018a: Unknown result type (might be due to invalid IL or missing references)
		//IL_018f: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)ringMesh != (Object)null)
		{
			return ringMesh;
		}
		List<Vector3> list = new List<Vector3>();
		List<Vector2> list2 = new List<Vector2>();
		Vector3 val = default(Vector3);
		for (int i = 0; i <= 64; i++)
		{
			float num = (float)i / 64f * (float)Math.PI * 2f;
			((Vector3)(ref val))..ctor(Mathf.Cos(num), 0f, Mathf.Sin(num));
			list.Add(val * 0.72f);
			list.Add(val);
			list2.Add(new Vector2((float)i / 64f, 0f));
			list2.Add(new Vector2((float)i / 64f, 1f));
		}
		List<int> list3 = new List<int>();
		for (int j = 0; j < 64; j++)
		{
			int num2 = j * 2;
			int num3 = num2 + 1;
			int num4 = num2 + 2;
			int num5 = num2 + 3;
			list3.AddRange(new int[6] { num2, num4, num3, num3, num4, num5 });
			list3.AddRange(new int[6] { num3, num4, num2, num5, num4, num3 });
		}
		ringMesh = new Mesh
		{
			name = "ResonanceShockwaveRing",
			hideFlags = (HideFlags)61
		};
		ringMesh.SetVertices(list);
		ringMesh.SetUVs(0, list2);
		ringMesh.SetTriangles(list3, 0);
		ringMesh.RecalculateNormals();
		ringMesh.bounds = new Bounds(Vector3.zero, Vector3.one * 2f);
		return ringMesh;
	}
}
public class ShockwaveAnimator : MonoBehaviour
{
	private static readonly int ColorId = Shader.PropertyToID("_Color");

	private static readonly int TintId = Shader.PropertyToID("_TintColor");

	private float radius;

	private float duration;

	private Color color;

	private float age;

	private Material instanceMaterial;

	public void Initialize(float radius, float duration, Color color)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		this.radius = radius;
		this.duration = Mathf.Max(duration, 0.05f);
		this.color = color;
		instanceMaterial = ((Renderer)((Component)this).GetComponent<MeshRenderer>()).material;
		Apply(0f);
	}

	private void Update()
	{
		age += Time.deltaTime;
		float num = Mathf.Clamp01(age / duration);
		Apply(num);
		if (num >= 1f)
		{
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}
	}

	private void Apply(float t)
	{
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: 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_00a7: Unknown result type (might be due to invalid IL or missing references)
		float num = 1f - Mathf.Pow(1f - t, 3f);
		float num2 = Mathf.Max(radius * num, 0.01f);
		((Component)this).transform.localScale = new Vector3(num2, num2, num2);
		Color val = color;
		val.a = color.a * (1f - t) * (1f - t);
		if (instanceMaterial.HasProperty(ColorId))
		{
			instanceMaterial.SetColor(ColorId, val);
		}
		if (instanceMaterial.HasProperty(TintId))
		{
			instanceMaterial.SetColor(TintId, val);
		}
	}

	private void OnDestroy()
	{
		if ((Object)(object)instanceMaterial != (Object)null)
		{
			Object.Destroy((Object)(object)instanceMaterial);
		}
	}
}