Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of CombatMomentumPlus v1.1.0
CombatMomentumPlus.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using CombatMomentum.Managers; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("CombatMomentum")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("CombatMomentum")] [assembly: AssemblyTitle("CombatMomentum")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace CombatMomentum { [BepInPlugin("com.senez.combatmomentum", "Combat Momentum", "1.0.0")] public class CombatMomentum : BaseUnityPlugin { public const string ModGUID = "com.senez.combatmomentum"; public const string ModName = "Combat Momentum"; public const string ModVersion = "1.0.0"; public static CombatMomentum Instance; public static string AssetPath = Path.Combine(Paths.PluginPath, "CombatMomentum", "Assets"); internal static ManualLogSource Log; private Harmony _harmony; private void Awake() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown Instance = this; MomentumConfig.Bind(((BaseUnityPlugin)this).Config); Log = ((BaseUnityPlugin)this).Logger; string[] manifestResourceNames = Assembly.GetExecutingAssembly().GetManifestResourceNames(); foreach (string text in manifestResourceNames) { Log.LogInfo((object)("RESOURCE: " + text)); } _harmony = new Harmony("com.senez.combatmomentum"); _harmony.PatchAll(); Log.LogInfo((object)"========================================"); Log.LogInfo((object)"Combat Momentum v1.0.0 loaded!"); Log.LogInfo((object)"Combat Momentum initialized successfully."); Log.LogInfo((object)"========================================"); } private void Update() { MomentumManager.Update(Time.deltaTime); } } public static class EmbeddedAssets { public static Sprite LoadSprite(string name) { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_00d1: 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) Assembly executingAssembly = Assembly.GetExecutingAssembly(); string text = null; string[] manifestResourceNames = executingAssembly.GetManifestResourceNames(); foreach (string text2 in manifestResourceNames) { if (text2.EndsWith(name)) { text = text2; break; } } if (text == null) { CombatMomentum.Log.LogError((object)("Resource not found: " + name)); return null; } byte[] array; using (Stream stream = executingAssembly.GetManifestResourceStream(text)) { using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); array = memoryStream.ToArray(); } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(val, array)) { CombatMomentum.Log.LogError((object)("Failed to decode image: " + name)); return null; } return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)); } } public static class MomentumConfig { public const int MaxStacks = 5; private const float DefaultDuration = 10f; private static ConfigEntry<float>[] _attackSpeed; private static ConfigEntry<float>[] _damage; private static ConfigEntry<float>[] _critChance; private static ConfigEntry<float>[] _duration; public static void Bind(ConfigFile config) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Expected O, but got Unknown //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Expected O, but got Unknown _attackSpeed = new ConfigEntry<float>[5]; _damage = new ConfigEntry<float>[5]; _critChance = new ConfigEntry<float>[5]; _duration = new ConfigEntry<float>[5]; for (int i = 0; i < 5; i++) { int num = i + 1; string text = "Stack " + num; _attackSpeed[i] = config.Bind<float>(text, "Attack Speed Bonus (%)", (float)num * 8f, new ConfigDescription("Attack speed bonus while at " + num + " stack(s).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 500f), Array.Empty<object>())); _damage[i] = config.Bind<float>(text, "Damage Bonus (%)", (float)num * 10f, new ConfigDescription("Damage bonus while at " + num + " stack(s).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1000f), Array.Empty<object>())); _critChance[i] = config.Bind<float>(text, "Crit Chance (%)", (num >= 5) ? 20f : 0f, new ConfigDescription("Chance for a double-damage hit while at " + num + " stack(s).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); _duration[i] = config.Bind<float>(text, "Duration (s)", 10f, new ConfigDescription("Seconds the stack lasts when gained, and when falling back to " + num + " stack(s).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 600f), Array.Empty<object>())); } } public static float AttackSpeedMultiplier(int stacks) { return 1f + AttackSpeedPercent(stacks) / 100f; } public static float DamageMultiplier(int stacks) { return 1f + DamagePercent(stacks) / 100f; } public static float AttackSpeedPercent(int stacks) { return Get(_attackSpeed, stacks, 0f); } public static float DamagePercent(int stacks) { return Get(_damage, stacks, 0f); } public static float CritChance(int stacks) { return Get(_critChance, stacks, 0f) / 100f; } public static float Duration(int stacks) { return Get(_duration, stacks, 10f); } private static float Get(ConfigEntry<float>[] entries, int stacks, float fallback) { if (entries == null || stacks < 1) { return fallback; } return entries[((stacks > 5) ? 5 : stacks) - 1].Value; } } } namespace CombatMomentum.Patches { [HarmonyPatch(typeof(Hud), "Update")] public static class HudPatch { private static GameObject _panel; private static Text _title; private static Text _damage; private static Text _speedText; private static Text _timeText; private static Image _timerFill; private static List<Image> _runes = new List<Image>(); private static List<Outline> _runeOutlines = new List<Outline>(); private static int _lastRuneCount = 0; private static float _runeFlash = 0f; private static int _lastStacks = 0; private static float _pulseTimer = 0f; private static float _runePulse = 0f; private static float _maxPulse = 0f; private static Sprite _whiteSprite; private static Color _gold = new Color(1f, 0.75f, 0.25f, 1f); private static Color _orange = new Color(1f, 0.45f, 0.1f, 1f); private static Color _red = new Color(1f, 0.15f, 0.05f, 1f); private static void Postfix(Hud __instance) { //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null) { return; } if ((Object)(object)_panel == (Object)null) { CreateUI(__instance); CreateTopLine(); } int current = MomentumManager.Current; if (current <= 0) { _panel.SetActive(false); _lastStacks = 0; return; } _panel.SetActive(true); _runePulse += Time.deltaTime; _maxPulse += Time.deltaTime; UpdateRunes(current); _damage.text = "+" + MomentumConfig.DamagePercent(current).ToString("0.##") + "% DAMAGE"; _speedText.text = "+" + MomentumConfig.AttackSpeedPercent(current).ToString("0.##") + "% SPEED"; if (current >= 5) { ((Graphic)_title).color = Color.Lerp(Color.yellow, Color.red, Mathf.PingPong(Time.time, 1f)); } else { ((Graphic)_title).color = Color.white; } float timeRemaining = MomentumManager.TimeRemaining; _timeText.text = timeRemaining.ToString("0.0") + "s"; float num = timeRemaining / MomentumManager.MaxTime; float num2 = Mathf.Lerp(((Transform)((Graphic)_timerFill).rectTransform).localScale.x, num, Time.deltaTime * 8f); ((Transform)((Graphic)_timerFill).rectTransform).localScale = new Vector3(num2, 1f, 1f); if (current > _lastStacks) { _pulseTimer = 0.25f; } _lastStacks = current; if (_pulseTimer > 0f) { _pulseTimer -= Time.deltaTime; float num3 = 1f + _pulseTimer; _panel.transform.localScale = Vector3.one * num3; } else { _panel.transform.localScale = Vector3.one; } } private static void UpdateRunes(int stacks) { //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: 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_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) if (stacks > _lastRuneCount) { _runeFlash = 0.35f; } _lastRuneCount = stacks; if (_runeFlash > 0f) { _runeFlash -= Time.deltaTime; } float num = 1f + Mathf.Sin(_runePulse * 4f) * 0.05f; for (int i = 0; i < _runes.Count; i++) { if (i < stacks) { Color val = _gold; if (stacks >= 3) { val = _orange; } if (stacks >= 5) { val = Color.Lerp(_orange, _red, Mathf.PingPong(_maxPulse, 1f)); } ((Graphic)_runes[i]).color = val; ((Shadow)_runeOutlines[i]).effectColor = new Color(val.r, val.g, val.b, 0.8f); ((Component)_runes[i]).transform.localScale = Vector3.one * num; if (_runeFlash > 0f) { float num2 = 1f + _runeFlash * 2f; ((Component)_runes[i]).transform.localScale = Vector3.one * num2; } } else { ((Graphic)_runes[i]).color = new Color(0.12f, 0.12f, 0.12f, 1f); ((Component)_runes[i]).transform.localScale = Vector3.one; } } } private static void CreateTopLine() { //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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("TopLine"); val.transform.SetParent(_panel.transform, false); RectTransform obj = val.AddComponent<RectTransform>(); obj.sizeDelta = new Vector2(240f, 2f); obj.anchoredPosition = new Vector2(0f, 55f); ((Graphic)val.AddComponent<Image>()).color = new Color(1f, 0.65f, 0.2f, 0.8f); } private static void CreateRunes() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0093: 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_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) _runes.Clear(); _runeOutlines.Clear(); for (int i = 0; i < 5; i++) { GameObject val = new GameObject("Rune_" + i); val.transform.SetParent(_panel.transform, false); RectTransform obj = val.AddComponent<RectTransform>(); obj.sizeDelta = new Vector2(16f, 16f); obj.anchoredPosition = new Vector2((float)(-48 + i * 24), 5f); ((Transform)obj).localRotation = Quaternion.Euler(0f, 0f, 45f); Image val2 = val.AddComponent<Image>(); val2.sprite = GetWhiteSprite(); ((Graphic)val2).color = new Color(0.12f, 0.12f, 0.12f, 1f); Outline val3 = val.AddComponent<Outline>(); ((Shadow)val3).effectColor = new Color(0f, 0f, 0f, 0.7f); ((Shadow)val3).effectDistance = new Vector2(1f, -1f); _runeOutlines.Add(val3); _runes.Add(val2); } } private static Sprite GetWhiteSprite() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown if ((Object)(object)_whiteSprite != (Object)null) { return _whiteSprite; } Texture2D val = new Texture2D(1, 1); val.SetPixel(0, 0, Color.white); val.Apply(); _whiteSprite = Sprite.Create(val, new Rect(0f, 0f, 1f, 1f), new Vector2(0.5f, 0.5f)); return _whiteSprite; } private static void CreateUI(Hud hud) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: 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_0126: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Expected O, but got Unknown //IL_01fb: 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_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) _panel = new GameObject("CombatMomentumHUD"); _panel.transform.SetParent(((Component)hud).transform, false); RectTransform obj = _panel.AddComponent<RectTransform>(); obj.anchorMin = new Vector2(0f, 0f); obj.anchorMax = new Vector2(0f, 0f); obj.pivot = new Vector2(0f, 0f); obj.anchoredPosition = new Vector2(260f, 70f); obj.sizeDelta = new Vector2(240f, 120f); GameObject val = new GameObject("Background"); val.transform.SetParent(_panel.transform, false); RectTransform obj2 = val.AddComponent<RectTransform>(); obj2.anchorMin = Vector2.zero; obj2.anchorMax = Vector2.one; obj2.offsetMin = Vector2.zero; obj2.offsetMax = Vector2.zero; ((Graphic)val.AddComponent<Image>()).color = new Color(0.015f, 0.012f, 0.008f, 0.85f); Outline obj3 = val.AddComponent<Outline>(); ((Shadow)obj3).effectColor = new Color(1f, 0.65f, 0.2f, 0.6f); ((Shadow)obj3).effectDistance = new Vector2(2f, 2f); _title = CreateText("⚔ MOMENTUM", 18, new Vector2(0f, 35f)); CreateRunes(); _damage = CreateText("+0% DAMAGE", 16, new Vector2(0f, -20f)); _speedText = CreateText("+0% SPEED", 14, new Vector2(0f, -38f)); _timeText = CreateText("10s", 14, new Vector2(85f, -25f)); GameObject val2 = new GameObject("TimerBar"); val2.transform.SetParent(_panel.transform, false); RectTransform obj4 = val2.AddComponent<RectTransform>(); obj4.sizeDelta = new Vector2(170f, 6f); obj4.anchoredPosition = new Vector2(0f, -55f); ((Graphic)val2.AddComponent<Image>()).color = new Color(0.15f, 0.15f, 0.15f, 1f); GameObject val3 = new GameObject("Fill"); val3.transform.SetParent(val2.transform, false); RectTransform obj5 = val3.AddComponent<RectTransform>(); obj5.anchorMin = Vector2.zero; obj5.anchorMax = Vector2.one; obj5.offsetMin = Vector2.zero; obj5.offsetMax = Vector2.zero; _timerFill = val3.AddComponent<Image>(); _timerFill.sprite = GetWhiteSprite(); ((Graphic)_timerFill).color = new Color(1f, 0.7f, 0.2f, 1f); } private static Text CreateText(string value, int size, Vector2 position) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_004d: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Text"); val.transform.SetParent(_panel.transform, false); Text obj = val.AddComponent<Text>(); obj.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf"); obj.fontSize = size; obj.text = value; obj.alignment = (TextAnchor)4; ((Graphic)obj).color = Color.white; Shadow obj2 = val.AddComponent<Shadow>(); obj2.effectColor = Color.black; obj2.effectDistance = new Vector2(1f, -1f); RectTransform component = ((Component)obj).GetComponent<RectTransform>(); component.sizeDelta = new Vector2(220f, 25f); component.anchoredPosition = position; return obj; } } [HarmonyPatch(typeof(Humanoid))] public static class MomentumAttackAnimationPatch { private static float _lastSet = -1f; private static float _gameSpeed = 1f; [HarmonyPatch("UpdateAttack")] [HarmonyPostfix] private static void Postfix(Humanoid __instance) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } Animator componentInChildren = ((Component)__instance).GetComponentInChildren<Animator>(); if ((Object)(object)componentInChildren == (Object)null) { return; } float speed = componentInChildren.speed; if (!(speed < 0.01f)) { if (_lastSet < 0f || !Mathf.Approximately(speed, _lastSet)) { _gameSpeed = speed; } int current = MomentumManager.Current; float num = ((current > 0 && ((Character)__instance).InAttack()) ? MomentumConfig.AttackSpeedMultiplier(current) : 1f); float num2 = _gameSpeed * num; if (!Mathf.Approximately(speed, num2)) { componentInChildren.speed = num2; } _lastSet = num2; } } } [HarmonyPatch(typeof(HitData))] public static class MomentumAttackPatch { [HarmonyPatch("GetTotalDamage")] [HarmonyPostfix] private static void Postfix(HitData __instance, ref float __result) { if ((Object)(object)__instance.GetAttacker() != (Object)(object)Player.m_localPlayer) { return; } int current = MomentumManager.Current; if (current > 0) { __result *= MomentumConfig.DamageMultiplier(current); if (Random.value < MomentumConfig.CritChance(current)) { __result *= 2f; } } } } [HarmonyPatch(typeof(Humanoid), "BlockAttack")] public static class PerfectParryPatch { private static FieldInfo blockTimerField = AccessTools.Field(typeof(Humanoid), "m_blockTimer"); private static void Postfix(Humanoid __instance, HitData hit, Character attacker, bool __result) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) if (__result && !((Object)(object)attacker == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !(blockTimerField == null)) { float num = (float)blockTimerField.GetValue(__instance); if (num != -1f && num < 0.25f) { MomentumManager.AddStack(); attacker.Stagger(-hit.m_dir); } } } } } namespace CombatMomentum.Managers { public static class MomentumManager { private static float _timer; private static int _stacks; public static int Stacks => _stacks; public static float MaxTime => MomentumConfig.Duration(_stacks); public static float TimeRemaining => _timer; public static int Current => _stacks; public static void AddStack() { if (_stacks < 5) { _stacks++; } _timer = MomentumConfig.Duration(_stacks); } public static void RemoveStack() { if (_stacks > 0) { _stacks--; } } public static void Reset() { _stacks = 0; _timer = 0f; } public static void Update(float deltaTime) { if (_stacks > 0) { _timer -= deltaTime; if (_timer <= 0f) { RemoveStack(); _timer = MomentumConfig.Duration(_stacks); } } } } }