Decompiled source of God Mode and One Hit Kill No Menu v1.0.0

GodModeOneHitKill.dll

Decompiled 9 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using OffTheClock.Shared;
using Rewired;
using RoR2;
using RoR2.UI;
using UnityEngine;
using UnityEngine.Networking;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace GodModeOneHitKill
{
	[BepInPlugin("offtheclock.ror2godmode", "God Mode and One Hit Kill", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> GodMode;

		internal static ConfigEntry<bool> OneHitKill;

		private ConfigEntry<KeyCode> _godKey;

		private ConfigEntry<KeyCode> _ohkKey;

		private ConfigEntry<bool> _showNotice;

		private Notice _notice;

		private readonly HashSet<HealthComponent> _ours = new HashSet<HealthComponent>();

		private bool _inRunSeen;

		private bool _offlineRefusalLogged;

		private bool _keysBroken;

		private bool _godBroken;

		private bool _godLogged;

		private void Awake()
		{
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Expected O, but got Unknown
			//IL_0121: Expected O, but got Unknown
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			_notice = new Notice("God Mode and One Hit Kill");
			GodMode = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "GodMode", false, "You take no damage (the game's own god mode switch on your character). The key below flips this and it is saved.");
			OneHitKill = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "OneHitKill", false, "Your own hits kill any enemy in one hit (drones and turrets hit normally). The key below flips this and it is saved.");
			_godKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keys", "GodModeKey", (KeyCode)257, "Turns god mode on/off. Numpad digits need Num Lock on. None = no key.");
			_ohkKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keys", "OneHitKillKey", (KeyCode)258, "Turns one hit kill on/off. Numpad digits need Num Lock on. None = no key.");
			_showNotice = ((BaseUnityPlugin)this).Config.Bind<bool>("Keys", "ShowOnScreenNotice", true, "Show ON/OFF on screen for a moment after a key press (it is always written to the log).");
			Harmony val = new Harmony("offtheclock.ror2godmode");
			Honesty.MarkRunChanging(val, Log, "God Mode and One Hit Kill");
			bool flag = PatchGuard.Apply(val, Log, "God Mode and One Hit Kill", "RoR2.HealthComponent", "TakeDamage", new Type[1] { typeof(DamageInfo) }, PatchGuard.Own(typeof(Patches), "TakeDamage_Pre"), null);
			Log.LogInfo((object)("God Mode and One Hit Kill 1.0.0 loaded - god mode " + OnOff(GodMode.Value) + " (" + KeyCheck.KeyName(_godKey.Value) + "), one hit kill " + (flag ? OnOff(OneHitKill.Value) : "INACTIVE (game function not found)") + " (" + KeyCheck.KeyName(_ohkKey.Value) + "); solo and local split-screen only (never online)."));
		}

		internal static string OnOff(bool b)
		{
			if (!b)
			{
				return "OFF";
			}
			return "ON";
		}

		private void Update()
		{
			ReadKeys();
			ApplyGod();
		}

		private void ReadKeys()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (_keysBroken)
			{
				return;
			}
			try
			{
				if (KeyCheck.Pressed(_godKey.Value))
				{
					Toggle(GodMode, "God mode");
				}
				if (KeyCheck.Pressed(_ohkKey.Value))
				{
					Toggle(OneHitKill, "One hit kill");
				}
			}
			catch (Exception ex)
			{
				_keysBroken = true;
				Log.LogWarning((object)("God Mode and One Hit Kill: key reading stopped (" + ex.Message + "); the config values still work."));
			}
		}

		private void Toggle(ConfigEntry<bool> entry, string what)
		{
			entry.Value = !entry.Value;
			bool flag = Session.InRun && !Session.IsOffline;
			Log.LogInfo((object)("God Mode and One Hit Kill: " + what + " " + OnOff(entry.Value) + (flag ? (" - not applied: " + Session.Describe() + " (offline only).") : ".")));
			_notice.Show(what + " " + OnOff(entry.Value) + (flag ? " (offline only)" : ""));
			_godLogged = false;
		}

		private void ApplyGod()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			if (_godBroken)
			{
				return;
			}
			try
			{
				bool inRun = Session.InRun;
				if (inRun && !_inRunSeen)
				{
					_inRunSeen = true;
					_offlineRefusalLogged = false;
					_godLogged = false;
					Patches.NewRun();
					KeyCheck.Check(Log, "God Mode and One Hit Kill", new List<KeyValuePair<string, KeyCode>>
					{
						new KeyValuePair<string, KeyCode>("god mode", _godKey.Value),
						new KeyValuePair<string, KeyCode>("one hit kill", _ohkKey.Value)
					});
				}
				else if (!inRun && _inRunSeen)
				{
					_inRunSeen = false;
					_ours.Clear();
				}
				bool isOffline = Session.IsOffline;
				bool num = GodMode.Value && inRun && isOffline;
				if (inRun && !isOffline && (GodMode.Value || OneHitKill.Value) && !_offlineRefusalLogged)
				{
					_offlineRefusalLogged = true;
					Log.LogInfo((object)("God Mode and One Hit Kill: off in this run (" + Session.Describe() + ") - works in solo and local split-screen only."));
					_notice.Show("God Mode / One Hit Kill: offline only");
				}
				if (num)
				{
					foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList)
					{
						CharacterBody val = ((readOnlyLocalUsers != null) ? readOnlyLocalUsers.cachedBody : null);
						if (Object.op_Implicit((Object)(object)val))
						{
							HealthComponent healthComponent = val.healthComponent;
							if (Object.op_Implicit((Object)(object)healthComponent) && !healthComponent.godMode)
							{
								healthComponent.godMode = true;
								_ours.Add(healthComponent);
								if (!_godLogged)
								{
									_godLogged = true;
									Log.LogInfo((object)("God Mode and One Hit Kill: god mode applied to " + val.GetDisplayName() + " (" + Session.Describe() + ")."));
								}
							}
						}
					}
					return;
				}
				if (_ours.Count <= 0)
				{
					return;
				}
				foreach (HealthComponent our in _ours)
				{
					if (Object.op_Implicit((Object)(object)our))
					{
						our.godMode = false;
					}
				}
				_ours.Clear();
				Log.LogInfo((object)("God Mode and One Hit Kill: god mode removed (" + (GodMode.Value ? Session.Describe() : "turned off") + ")."));
			}
			catch (Exception ex)
			{
				_godBroken = true;
				Log.LogWarning((object)("God Mode and One Hit Kill: god mode stopped (" + ex.Message + ")."));
				try
				{
					foreach (HealthComponent our2 in _ours)
					{
						if (Object.op_Implicit((Object)(object)our2))
						{
							our2.godMode = false;
						}
					}
					_ours.Clear();
				}
				catch
				{
				}
			}
		}

		private void OnGUI()
		{
			_notice.Draw(Log, _showNotice.Value);
		}
	}
	internal static class Patches
	{
		private static bool _loggedKill;

		internal static void NewRun()
		{
			_loggedKill = false;
		}

		internal static void TakeDamage_Pre(HealthComponent __instance, DamageInfo damageInfo)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!Plugin.OneHitKill.Value || damageInfo == null || !Object.op_Implicit((Object)(object)damageInfo.attacker) || !Object.op_Implicit((Object)(object)__instance) || !Session.IsOffline)
				{
					return;
				}
				CharacterBody component = damageInfo.attacker.GetComponent<CharacterBody>();
				if (!Object.op_Implicit((Object)(object)component) || !component.isPlayerControlled)
				{
					return;
				}
				CharacterBody body = __instance.body;
				if (Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)body.teamComponent) && Object.op_Implicit((Object)(object)component.teamComponent) && body.teamComponent.teamIndex != component.teamComponent.teamIndex)
				{
					float num = (__instance.fullCombinedHealth + __instance.barrier) * 10f + 1000f;
					if (damageInfo.damage < num)
					{
						damageInfo.damage = num;
					}
					damageInfo.damageType |= DamageTypeCombo.op_Implicit((DamageType)262210);
					if (!_loggedKill)
					{
						_loggedKill = true;
						Plugin.Log.LogInfo((object)("God Mode and One Hit Kill: one hit kill active (first hit on " + body.GetDisplayName() + ")."));
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogDebug((object)("God Mode and One Hit Kill: one hit kill skipped once (" + ex.Message + ")."));
			}
		}
	}
	internal static class PluginInfo
	{
		public const string PLUGIN_GUID = "offtheclock.ror2godmode";

		public const string PLUGIN_NAME = "God Mode and One Hit Kill";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace OffTheClock.Shared
{
	internal static class Honesty
	{
		private static ManualLogSource _log;

		private static string _feature;

		private static bool _loggedBlock;

		internal static void MarkRunChanging(Harmony harmony, ManualLogSource log, string feature)
		{
			_log = log;
			_feature = feature;
			bool flag = false;
			bool flag2 = false;
			try
			{
				RoR2Application.isModded = true;
				flag = true;
			}
			catch (Exception ex)
			{
				log.LogWarning((object)(feature + ": could not set the game's modded flag: " + ex.Message));
			}
			try
			{
				MethodInfo methodInfo = AccessTools.PropertySetter(typeof(Console), "sessionCheatsEnabled");
				if (methodInfo != null)
				{
					methodInfo.Invoke(null, new object[1] { true });
					flag2 = Console.sessionCheatsEnabled;
				}
				if (!flag2)
				{
					log.LogWarning((object)(feature + ": the game's cheat flag (Console.sessionCheatsEnabled) could not be set; the leaderboard lock below still applies."));
				}
			}
			catch (Exception ex2)
			{
				log.LogWarning((object)(feature + ": could not set the game's cheat flag: " + ex2.Message));
			}
			bool flag3 = PatchGuard.Apply(harmony, log, feature, "RoR2.WeeklyRun", "GetLeaderboardName", new Type[2]
			{
				typeof(int),
				typeof(uint)
			}, null, PatchGuard.Own(typeof(Honesty), "GetLeaderboardName_Post"));
			log.LogInfo((object)(feature + ": Prismatic Trials leaderboard blocked for this session (modded flag " + (flag ? "set" : "NOT set") + ", cheat flag " + (flag2 ? "set" : "NOT set") + ", leaderboard lock " + (flag3 ? "on" : "NOT on") + ")."));
		}

		private static void GetLeaderboardName_Post(ref string __result)
		{
			try
			{
				__result = null;
				if (!_loggedBlock)
				{
					_loggedBlock = true;
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogInfo((object)(_feature + ": Prismatic Trials leaderboard name refused (modded session: no score is submitted and the leaderboard view stays empty)."));
					}
				}
			}
			catch
			{
			}
		}
	}
	internal static class KeyCheck
	{
		internal static void Check(ManualLogSource log, string feature, IList<KeyValuePair<string, KeyCode>> keys)
		{
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!ReInput.isReady)
				{
					return;
				}
				List<string> list = new List<string>();
				foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList)
				{
					Player val = ((readOnlyLocalUsers != null) ? readOnlyLocalUsers.inputPlayer : null);
					if (val == null)
					{
						continue;
					}
					foreach (ControllerMap allMap in val.controllers.maps.GetAllMaps((ControllerType)0))
					{
						if (allMap == null || !allMap.enabled)
						{
							continue;
						}
						foreach (ActionElementMap allMap2 in allMap.AllMaps)
						{
							if (allMap2 == null || (int)allMap2.keyCode == 0)
							{
								continue;
							}
							foreach (KeyValuePair<string, KeyCode> key in keys)
							{
								if ((int)key.Value != 0 && allMap2.keyCode == key.Value)
								{
									string text = "action " + allMap2.actionId;
									try
									{
										InputAction action = ReInput.mapping.GetAction(allMap2.actionId);
										text = ((action != null) ? action.name : null) ?? text;
									}
									catch
									{
									}
									list.Add(KeyName(key.Value) + " (" + key.Key + ") is also bound to the game's '" + text + "'");
								}
							}
						}
					}
				}
				if (list.Count == 0)
				{
					log.LogInfo((object)(feature + ": key check - " + List(keys) + " not used by your game key bindings."));
				}
				else
				{
					log.LogWarning((object)(feature + ": key clash - " + string.Join("; ", list) + ". Change the key in the config or in the game's Settings > Keyboard."));
				}
			}
			catch (Exception ex)
			{
				log.LogInfo((object)(feature + ": key check skipped (" + ex.Message + ")."));
			}
		}

		internal static string List(IList<KeyValuePair<string, KeyCode>> keys)
		{
			//IL_0018: 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)
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, KeyCode> key in keys)
			{
				if ((int)key.Value != 0)
				{
					list.Add(KeyName(key.Value));
				}
			}
			if (list.Count != 0)
			{
				return string.Join(", ", list);
			}
			return "(no keys)";
		}

		internal unsafe static string KeyName(KeyCode k)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected I4, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Invalid comparison between Unknown and I4
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Invalid comparison between Unknown and I4
			//IL_0068: 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_0070: Expected I4, but got Unknown
			if ((int)k != 0)
			{
				switch (k - 266)
				{
				case 2:
					return "Numpad *";
				case 1:
					return "Numpad /";
				case 4:
					return "Numpad +";
				case 3:
					return "Numpad -";
				case 0:
					return "Numpad .";
				case 5:
					return "Numpad Enter";
				default:
					if ((int)k >= 256 && (int)k <= 265)
					{
						return "Numpad " + (k - 256);
					}
					return ((object)(*(KeyCode*)(&k))/*cast due to .constrained prefix*/).ToString();
				}
			}
			return "(no key)";
		}

		internal static bool Pressed(KeyCode k)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			if ((int)k != 0 && Input.GetKeyDown(k))
			{
				return !Session.IsTyping;
			}
			return false;
		}
	}
	internal sealed class Notice
	{
		private const float Seconds = 2.5f;

		private readonly string _feature;

		private string _text;

		private float _until;

		private bool _broken;

		internal Notice(string feature)
		{
			_feature = feature;
		}

		internal void Show(string text)
		{
			_text = text;
			_until = Time.unscaledTime + 2.5f;
		}

		internal void Draw(ManualLogSource log, bool enabled)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			if (_broken || !enabled || _text == null || Time.unscaledTime > _until)
			{
				return;
			}
			try
			{
				float num = Mathf.Max(320f, 14f * (float)_text.Length);
				float num2 = 44f;
				Rect val = new Rect(((float)Screen.width - num) / 2f, (float)Screen.height * 0.12f, num, num2);
				GUI.Box(val, "");
				GUI.Box(val, "");
				GUIStyle label = GUI.skin.label;
				int fontSize = label.fontSize;
				TextAnchor alignment = label.alignment;
				label.fontSize = 24;
				label.alignment = (TextAnchor)4;
				GUI.Label(val, _text, label);
				label.fontSize = fontSize;
				label.alignment = alignment;
			}
			catch (Exception ex)
			{
				_broken = true;
				log.LogWarning((object)(_feature + ": on-screen notice unavailable (" + ex.Message + "); new values are shown in the log only."));
			}
		}
	}
	internal static class PatchGuard
	{
		internal static bool Apply(Harmony harmony, ManualLogSource log, string feature, string typeName, string methodName, Type[] parameters, MethodInfo prefix, MethodInfo postfix)
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Type type = AccessTools.TypeByName(typeName);
				if (type == null)
				{
					log.LogWarning((object)(feature + ": game class " + typeName + " not found - this part is skipped (game update?)."));
					return false;
				}
				MethodInfo methodInfo = ((parameters == null) ? AccessTools.Method(type, methodName, (Type[])null, (Type[])null) : AccessTools.Method(type, methodName, parameters, (Type[])null));
				if (methodInfo == null)
				{
					log.LogWarning((object)(feature + ": game method " + typeName + "." + methodName + " not found - this part is skipped (game update?)."));
					return false;
				}
				harmony.Patch((MethodBase)methodInfo, (prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(prefix), (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(postfix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				log.LogInfo((object)(feature + ": patched " + typeName + "." + methodName + "."));
				return true;
			}
			catch (Exception ex)
			{
				log.LogWarning((object)(feature + ": could not patch " + typeName + "." + methodName + " - this part is skipped (game update?): " + ex.Message));
				return false;
			}
		}

		internal static MethodInfo Own(Type patchClass, string name)
		{
			return AccessTools.Method(patchClass, name, (Type[])null, (Type[])null);
		}
	}
	internal static class Session
	{
		internal static bool InRun
		{
			get
			{
				try
				{
					return Object.op_Implicit((Object)(object)Run.instance);
				}
				catch
				{
					return false;
				}
			}
		}

		internal static bool IsSolo
		{
			get
			{
				try
				{
					return RoR2Application.isInSinglePlayer;
				}
				catch
				{
					return false;
				}
			}
		}

		internal static bool IsOffline
		{
			get
			{
				try
				{
					return NetworkServer.active && NetworkServer.dontListen;
				}
				catch
				{
					return false;
				}
			}
		}

		internal static bool IsTyping
		{
			get
			{
				try
				{
					return Object.op_Implicit((Object)(object)ConsoleWindow.instance) || ChatBox.IsActive;
				}
				catch
				{
					return false;
				}
			}
		}

		internal static string Describe()
		{
			try
			{
				if (!InRun)
				{
					return "not in a run";
				}
				if (IsSolo)
				{
					return "solo";
				}
				if (IsOffline)
				{
					return "local split-screen";
				}
				return "online lobby";
			}
			catch (Exception)
			{
				return "unknown";
			}
		}
	}
	internal static class Steps
	{
		internal static float[] Parse(string text, float min, float max, float[] fallback, ManualLogSource log, string feature, string name)
		{
			List<float> list = new List<float>();
			string[] array = (text ?? "").Split(new char[3] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				if (float.TryParse(array[i].Trim().TrimStart('x', 'X'), NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && result >= min && result <= max && !list.Contains(result))
				{
					list.Add(result);
				}
			}
			if (list.Count == 0)
			{
				log.LogWarning((object)(feature + ": " + name + " has no valid values (" + F(min) + " to " + F(max) + "), using " + Text(fallback) + "."));
				return fallback;
			}
			list.Sort();
			return list.ToArray();
		}

		internal static string F(float v)
		{
			return v.ToString("0.##", CultureInfo.InvariantCulture);
		}

		internal static string Text(float[] steps)
		{
			List<string> list = new List<string>();
			foreach (float v in steps)
			{
				list.Add("x" + F(v));
			}
			return string.Join("/", list);
		}

		internal static float NextCycle(float[] steps, float current)
		{
			foreach (float num in steps)
			{
				if (num > current + 0.001f)
				{
					return num;
				}
			}
			return steps[0];
		}

		internal static float Up(float[] steps, float current)
		{
			foreach (float num in steps)
			{
				if (num > current + 0.001f)
				{
					return num;
				}
			}
			return steps[^1];
		}

		internal static float Down(float[] steps, float current)
		{
			for (int num = steps.Length - 1; num >= 0; num--)
			{
				if (steps[num] < current - 0.001f)
				{
					return steps[num];
				}
			}
			return steps[0];
		}
	}
}