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);
}
}
}