using System; using System.Collections; 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 HarmonyLib; using Microsoft.CodeAnalysis; using Peak.Afflictions; using Photon.Pun; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.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 FatigueMod { [HarmonyPatch(typeof(Action_ApplyAffliction), "RunAction")] internal static class Action_ApplyAffliction_Patch { private static FieldInfo characterField; private static FieldInfo afflictionField; [HarmonyPrefix] private static void Prefix(Action_ApplyAffliction __instance) { //IL_00c2: Unknown result type (might be due to invalid IL or missing references) if (characterField == null) { characterField = typeof(ItemActionBase).GetField("character", BindingFlags.Instance | BindingFlags.NonPublic); } object? obj = characterField?.GetValue(__instance); Character val = (Character)((obj is Character) ? obj : null); if ((Object)(object)val == (Object)null || !val.IsLocal) { return; } if (afflictionField == null) { afflictionField = typeof(Action_ApplyAffliction).GetField("affliction", BindingFlags.Instance | BindingFlags.Public); } object? obj2 = afflictionField?.GetValue(__instance); Affliction val2 = (Affliction)((obj2 is Affliction) ? obj2 : null); if (val2 == null) { return; } FatiguePlugin.Logger.LogInfo((object)($"[DEBUG] Action_ApplyAffliction: {val2.GetAfflictionType()} " + "applied to " + val.characterName)); Affliction_InfiniteStamina val3 = (Affliction_InfiniteStamina)(object)((val2 is Affliction_InfiniteStamina) ? val2 : null); if (val3 != null) { FatigueAfflictionHandler.OnAfflictionApplied(val, (Affliction)(object)val3); return; } Affliction_FasterBoi val4 = (Affliction_FasterBoi)(object)((val2 is Affliction_FasterBoi) ? val2 : null); if (val4 != null) { FatigueAfflictionHandler.OnAfflictionApplied(val, (Affliction)(object)val4); } } } [HarmonyPatch(typeof(Action_GiveExtraStamina), "RunAction")] internal static class Action_GiveExtraStamina_Patch { private static FieldInfo characterField; [HarmonyPostfix] private static void Postfix(Action_GiveExtraStamina __instance) { if (characterField == null) { characterField = typeof(ItemActionBase).GetField("character", BindingFlags.Instance | BindingFlags.NonPublic); } object? obj = characterField?.GetValue(__instance); Character val = (Character)((obj is Character) ? obj : null); if ((Object)(object)val == (Object)null || !val.IsLocal) { return; } FatigueTracker component = ((Component)val).GetComponent(); if ((Object)(object)component == (Object)null) { return; } if (val.data.isSkeleton && !val.data.dead && !val.data.fullyPassedOut) { if (FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)"Skipping fatigue reduction - target is a living skeleton"); } return; } float amount = __instance.amount; float num = amount * FatiguePlugin.extraStaminaFatigueReductionRatio.Value; float fatigueValue = component.fatigueValue; component.fatigueValue = Mathf.Max(0f, component.fatigueValue - num); if (FatiguePlugin.debugMode.Value && num > 0.001f) { FatiguePlugin.Logger.LogInfo((object)($"Extra stamina ({amount:F2}) reduced fatigue by {num:F3} " + $"(from {fatigueValue:F3} to {component.fatigueValue:F3})")); } } } [HarmonyPatch(typeof(Action_ModifyStatus), "RunAction")] internal static class Action_ModifyStatus_Patch { private static HashSet processedCureAlls = new HashSet(); private static readonly HashSet healingItemIDs = new HashSet { 24 }; private static FieldInfo itemField; private static FieldInfo characterField; private static PropertyInfo characterProperty; [HarmonyPrefix] private static void Prefix(Action_ModifyStatus __instance) { if (itemField == null) { itemField = typeof(ItemActionBase).GetField("item", BindingFlags.Instance | BindingFlags.NonPublic); } object? obj = itemField?.GetValue(__instance); Item val = (Item)((obj is Item) ? obj : null); if ((Object)(object)val == (Object)null || val.itemID != 24 || processedCureAlls.Contains(val)) { return; } if (characterProperty == null) { characterProperty = typeof(ItemActionBase).GetProperty("character", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } Character val2 = null; if (characterProperty != null) { object? value = characterProperty.GetValue(__instance); val2 = (Character)((value is Character) ? value : null); } if ((Object)(object)val2 == (Object)null) { if (characterField == null) { characterField = typeof(ItemActionBase).GetField("character", BindingFlags.Instance | BindingFlags.NonPublic); } object? obj2 = characterField?.GetValue(__instance); val2 = (Character)((obj2 is Character) ? obj2 : null); } if ((Object)(object)val2 == (Object)null || !val2.IsLocal) { return; } if (val2.data.dead || val2.data.fullyPassedOut) { if (FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)"Skipping fatigue reduction - target is dead or passed out"); } return; } FatigueTracker component = ((Component)val2).GetComponent(); if (!((Object)(object)component == (Object)null)) { float num = 0.15f; float fatigueValue = component.fatigueValue; component.fatigueValue = Mathf.Max(0f, component.fatigueValue - num); processedCureAlls.Add(val); ((MonoBehaviour)__instance).StartCoroutine(CleanupProcessedItem(val)); if (FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)($"Cure-All consumed: Removed {num:F3} fatigue " + $"(from {fatigueValue:F3} to {component.fatigueValue:F3})")); } } } private static IEnumerator CleanupProcessedItem(Item item) { yield return (object)new WaitForSeconds(2f); processedCureAlls.Remove(item); } } [HarmonyPatch(typeof(CharacterData), "set_isSkeleton")] internal static class CharacterData_SetSkeleton_Patch { [HarmonyPostfix] private static void Postfix(CharacterData __instance, bool value) { if (!value) { return; } Character component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsLocal) { return; } Component component2 = ((Component)component).GetComponent("FatigueMod.FatigueTracker"); if ((Object)(object)component2 != (Object)null) { FieldInfo field = ((object)component2).GetType().GetField("fatigueValue", BindingFlags.Instance | BindingFlags.Public); if (field != null) { field.SetValue(component2, 0f); FatiguePlugin.Logger.LogInfo((object)"Cleared fatigue on skeleton transformation"); } } } } [HarmonyPatch(typeof(Affliction), "OnApplied")] internal static class Affliction_OnApplied_Patch { [HarmonyPostfix] private static void Postfix(Affliction __instance) { if (!((Object)(object)__instance.character == (Object)null) && (__instance is Affliction_InfiniteStamina || __instance is Affliction_FasterBoi)) { FatigueAfflictionHandler.OnAfflictionApplied(__instance.character, __instance); } } } [HarmonyPatch(typeof(Affliction), "OnRemoved")] internal static class Affliction_OnRemoved_Patch { [HarmonyPostfix] private static void Postfix(Affliction __instance) { if (!((Object)(object)__instance.character == (Object)null) && (__instance is Affliction_InfiniteStamina || __instance is Affliction_FasterBoi)) { FatigueAfflictionHandler.OnAfflictionRemoved(__instance.character, __instance); } } } [HarmonyPatch(typeof(BarAffliction), "ChangeAffliction")] internal static class BarAffliction_ChangeAffliction_Patch { [HarmonyPrefix] private static bool Prefix(BarAffliction __instance, StaminaBar bar) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (((Object)((Component)__instance).gameObject).name != "FatigueCustomBar") { return true; } Character observedCharacter = Character.observedCharacter; if ((Object)observedCharacter == (Object)null) { return false; } FatigueTracker component = ((Component)observedCharacter).GetComponent(); if ((Object)component == (Object)null) { return false; } float fatigueValue = component.fatigueValue; __instance.size = bar.fullBar.sizeDelta.x * fatigueValue; if (fatigueValue > 0.01f) { if (__instance.size < bar.minAfflictionWidth) { __instance.size = bar.minAfflictionWidth; } ((Component)__instance).gameObject.SetActive(true); } else { ((Component)__instance).gameObject.SetActive(false); } if (FatiguePlugin.debugMode.Value && Mathf.Abs(fatigueValue - FatiguePlugin._lastLoggedFatigue) > 0.05f) { FatiguePlugin._lastLoggedFatigue = fatigueValue; FatiguePlugin.Logger.LogInfo((object)$"Fatigue bar updated: value={fatigueValue:F3}, size={__instance.size:F1}"); } return false; } } [HarmonyPatch(typeof(BarAffliction), "UpdateAffliction")] internal static class BarAffliction_UpdateAffliction_Patch { [HarmonyPrefix] private static bool Prefix(BarAffliction __instance, StaminaBar bar) { if (((Object)((Component)__instance).gameObject).name != "FatigueCustomBar") { return true; } __instance.width = Mathf.Lerp(__instance.width, __instance.size, Mathf.Min(Time.deltaTime * 10f, 0.1f)); return false; } } [HarmonyPatch(typeof(CharacterAfflictions))] [HarmonyPatch(/*Could not decode attribute arguments.*/)] internal static class CharacterAfflictions_statusSum_Patch { [HarmonyPostfix] private static void Postfix(CharacterAfflictions __instance, ref float __result) { if (!((Object)(object)__instance.character == (Object)null)) { FatigueTracker component = ((Component)__instance.character).GetComponent(); if (!((Object)(object)component == (Object)null)) { __result += component.fatigueValue; } } } } [HarmonyPatch(typeof(Character), "AddExtraStamina")] internal static class Character_AddExtraStamina_Patch { [HarmonyPostfix] private static void Postfix(Character __instance, float add) { if (!__instance.IsLocal || add <= 0f) { return; } if (__instance.data.isSkeleton && !__instance.data.dead && !__instance.data.fullyPassedOut) { if (FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)"Skipping fatigue reduction - target is a living skeleton"); } return; } FatigueTracker component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null)) { float num = add * FatiguePlugin.extraStaminaFatigueReductionRatio.Value; float fatigueValue = component.fatigueValue; component.fatigueValue = Mathf.Max(0f, component.fatigueValue - num); if (FatiguePlugin.debugMode.Value && num > 0.001f) { FatiguePlugin.Logger.LogInfo((object)($"AddExtraStamina ({add:F2}) reduced fatigue by {num:F3} " + $"(from {fatigueValue:F3} to {component.fatigueValue:F3})")); } } } } [HarmonyPatch(typeof(Character), "Awake")] internal static class Character_Awake_Patch { [HarmonyPostfix] private static void Postfix(Character __instance) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown if ((Object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } if ((Object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } } } [HarmonyPatch(typeof(Character), "HasMeaningfulTempStatuses")] internal static class Character_HasMeaningfulTempStatuses_Patch { [HarmonyPostfix] private static void Postfix(Character __instance, ref bool __result) { FatigueTracker component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null) && !__result && component.fatigueValue > 0.05f) { __result = true; } } } [HarmonyPatch(typeof(Character), "UseStamina")] public static class Character_UseStamina_Patch { [HarmonyPostfix] public static void Postfix(Character __instance, float usage, bool useBonusStamina, ref bool __result) { if (__result && !(usage <= 0f) && !FatiguePlugin.IsFatigueDisabled()) { FatigueTracker component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null)) { component.OnStaminaUsed(usage); } } } } public static class FatigueAfflictionHandler { private class AfflictionData { public AfflictionType type; public float cachedFatigue; public float bonusFatigueOnEnd; public bool fatigueBlocked; } private static Dictionary activeAfflictions = new Dictionary(); public static void OnAfflictionApplied(Character character, Affliction affliction) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)character == (Object)null || !character.IsLocal) { return; } FatigueTracker component = ((Component)character).GetComponent(); if (!((Object)(object)component == (Object)null)) { int viewID = ((MonoBehaviourPun)character).photonView.ViewID; Affliction_FasterBoi val = (Affliction_FasterBoi)(object)((affliction is Affliction_FasterBoi) ? affliction : null); if (val != null) { AfflictionData afflictionData = new AfflictionData { type = (AfflictionType)2, cachedFatigue = component.fatigueValue, bonusFatigueOnEnd = 0.1f, fatigueBlocked = true }; activeAfflictions[viewID] = afflictionData; component.fatigueValue = 0f; FatiguePlugin.Logger.LogInfo((object)($"[Fatigue] Energy Drink consumed - Fatigue blocked for {((Affliction)val).totalTime:F1}s. " + $"Cached fatigue: {afflictionData.cachedFatigue:F3}, will add +{afflictionData.bonusFatigueOnEnd:F3} on end.")); } } } private static bool IsInvincible(Character character) { if ((Object)(object)character == (Object)null || (Object)(object)character.refs?.afflictions == (Object)null) { return false; } Affliction val = default(Affliction); if (character.refs.afflictions.HasAfflictionType((AfflictionType)14, ref val)) { return true; } if (character.refs.afflictions.HasAfflictionType((AfflictionType)16, ref val)) { return true; } return false; } public static void OnAfflictionRemoved(Character character, Affliction affliction) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Invalid comparison between Unknown and I4 if ((Object)(object)character == (Object)null || !character.IsLocal) { return; } FatigueTracker component = ((Component)character).GetComponent(); if ((Object)(object)component == (Object)null) { return; } int viewID = ((MonoBehaviourPun)character).photonView.ViewID; if (activeAfflictions.TryGetValue(viewID, out var value) && (int)value.type == 2 && affliction is Affliction_FasterBoi) { float num; if (IsInvincible(character)) { num = value.cachedFatigue; FatiguePlugin.Logger.LogInfo((object)("[Fatigue] Energy Drink effect ended - Character is INVINCIBLE (BingBongShield/Milk). " + $"Restored {value.cachedFatigue:F3} fatigue (NO BONUS added).")); } else { num = value.cachedFatigue + value.bonusFatigueOnEnd; FatiguePlugin.Logger.LogInfo((object)($"[Fatigue] Energy Drink effect ended - Restored {value.cachedFatigue:F3} " + $"+ bonus {value.bonusFatigueOnEnd:F3} = {num:F3}")); } component.fatigueValue = Mathf.Min(1f, num); activeAfflictions.Remove(viewID); } } public static bool IsFatigueBlocked(Character character) { if ((Object)(object)character == (Object)null) { return false; } int viewID = ((MonoBehaviourPun)character).photonView.ViewID; return activeAfflictions.ContainsKey(viewID); } } public static class FatigueBarInjector { public static BarAffliction injectedBar; private static bool injectionFailed; public static void TryInjectBar() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Invalid comparison between Unknown and I4 //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Expected O, but got Unknown //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Expected O, but got Unknown //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Expected O, but got Unknown //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Expected O, but got Unknown //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Expected O, but got Unknown //IL_0201: Expected O, but got Unknown //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Expected O, but got Unknown //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) if ((Object)injectedBar != (Object)null || injectionFailed) { return; } try { if ((Object)GUIManager.instance == (Object)null) { return; } StaminaBar bar = GUIManager.instance.bar; if ((Object)bar == (Object)null || bar.afflictions == null || bar.afflictions.Length == 0) { return; } BarAffliction val = null; BarAffliction[] afflictions = bar.afflictions; BarAffliction[] array = afflictions; foreach (BarAffliction val2 in array) { if (!((Object)val2 == (Object)null) && (int)val2.afflictionType == 4) { val = val2; break; } } if ((Object)val == (Object)null) { FatiguePlugin.Logger.LogWarning((object)"Crab template bar not found in StaminaBar.afflictions"); injectionFailed = true; return; } GameObject val3 = Object.Instantiate(((Component)val).gameObject, ((Component)val).transform.parent); ((Object)val3).name = "FatigueCustomBar"; BarAffliction component = val3.GetComponent(); if ((Object)component == (Object)null) { FatiguePlugin.Logger.LogError((object)"Cloned GameObject has no BarAffliction component"); Object.Destroy((Object)val3); injectionFailed = true; return; } if ((Object)FatiguePlugin.FatigueIconSprite != (Object)null && (Object)component.icon != (Object)null) { component.icon.sprite = FatiguePlugin.FatigueIconSprite; ((Graphic)component.icon).color = Color.white; } Image[] componentsInChildren = ((Component)component).GetComponentsInChildren(true); Image[] array2 = componentsInChildren; foreach (Image val4 in array2) { if (!((Object)component.icon != (Object)null) || !((Object)val4 == (Object)component.icon)) { Color fatigueColor = FatiguePlugin.FatigueColor; fatigueColor.a = ((Graphic)val4).color.a; ((Graphic)val4).color = fatigueColor; } } component.size = 0f; val3.SetActive(false); FieldInfo field = typeof(StaminaBar).GetField("afflictions", BindingFlags.Instance | BindingFlags.Public); if (field == null) { FatiguePlugin.Logger.LogError((object)"StaminaBar.afflictions field not found"); Object.Destroy((Object)val3); injectionFailed = true; return; } BarAffliction[] array3 = (BarAffliction[])field.GetValue(bar); BarAffliction[] array4 = (BarAffliction[])(object)new BarAffliction[array3.Length + 1]; Array.Copy(array3, array4, array3.Length); array4[array3.Length] = component; field.SetValue(bar, array4); injectedBar = component; if (FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)$"Independent bar injected. New array size: {array4.Length}"); } } catch (Exception arg) { FatiguePlugin.Logger.LogError((object)$"Bar injection failed: {arg}"); injectionFailed = true; } } } [BepInPlugin("jill920.fatiguefromstamina", "Fatigue Mod", "1.3.0")] public class FatiguePlugin : BaseUnityPlugin { public const string MOD_GUID = "jill920.fatiguefromstamina"; public static float _lastLoggedFatigue = -1f; public const string MOD_NAME = "Fatigue Mod"; public const string MOD_VERSION = "1.3.0"; public static FatiguePlugin Instance; public static ManualLogSource Logger; public static ConfigEntry debugMode; public static readonly Color FatigueColor = new Color(1f, 0.5f, 0f, 1f); public static Sprite FatigueIconSprite; public const string CUSTOM_BAR_NAME = "FatigueCustomBar"; public static ConfigEntry healingItemsConfig; public static ConfigEntry extraStaminaFatigueReductionRatio; public static ConfigEntry exertionWindowSeconds; public static ConfigEntry maxStaminaForExertion; public static ConfigEntry baseExertionRate; public static ConfigEntry maxExertionRate; public static ConfigEntry baseRecoveryRate; public static ConfigEntry zeroStaminaFatigue; public const float PLAY_DEAD_RECOVERY_MULTIPLIER = 1.66f; public const float ENERGY_DRINK_BONUS_FATIGUE = 0.1f; private void Awake() { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Expected O, but got Unknown //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0138: 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 //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Expected O, but got Unknown //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Expected O, but got Unknown healingItemsConfig = ((BaseUnityPlugin)this).Config.Bind("Healing", "HealingItemIDs", "24", "Comma-separated list of item IDs that reduce fatigue when used"); extraStaminaFatigueReductionRatio = ((BaseUnityPlugin)this).Config.Bind("Recovery", "ExtraStaminaFatigueReductionRatio", 0.4f, "Amount of fatigue removed per unit of extra stamina given."); exertionWindowSeconds = ((BaseUnityPlugin)this).Config.Bind("Exertion", "ExertionWindowSeconds", 120f, new ConfigDescription("Time window (in seconds) for tracking stamina usage. Larger = exertion persists longer.", (AcceptableValueBase)(object)new AcceptableValueRange(10f, 300f), Array.Empty())); maxStaminaForExertion = ((BaseUnityPlugin)this).Config.Bind("Exertion", "MaxStaminaForExertion", 8f, new ConfigDescription("Total stamina needed within the window to reach max exertion (1.0). Lower = easier to max exertion.", (AcceptableValueBase)(object)new AcceptableValueRange(2f, 20f), Array.Empty())); baseExertionRate = ((BaseUnityPlugin)this).Config.Bind("FatigueGain", "BaseExertionRate", 0.04f, new ConfigDescription("Fatigue gained per stamina used when exertion is 0 (rested).", (AcceptableValueBase)(object)new AcceptableValueRange(0.02f, 0.1f), Array.Empty())); maxExertionRate = ((BaseUnityPlugin)this).Config.Bind("FatigueGain", "MaxExertionRate", 0.16f, new ConfigDescription("Fatigue gained per stamina used when exertion is 1.0 (fully exerted).", (AcceptableValueBase)(object)new AcceptableValueRange(0.08f, 0.25f), Array.Empty())); baseRecoveryRate = ((BaseUnityPlugin)this).Config.Bind("FatigueRecovery", "BaseRecoveryRate", 0.0045f, new ConfigDescription("Fatigue recovered per second at full recovery (no exertion penalty).", (AcceptableValueBase)(object)new AcceptableValueRange(0.002f, 0.015f), Array.Empty())); zeroStaminaFatigue = ((BaseUnityPlugin)this).Config.Bind("Penalties", "ZeroStaminaFatigue", 0.035f, new ConfigDescription("Fatigue added (as percentage of max fatigue) when stamina is completely drained.", (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 0.1f), Array.Empty())); Instance = this; Logger = ((BaseUnityPlugin)this).Logger; debugMode = ((BaseUnityPlugin)this).Config.Bind("Debug", "EnableDebugKeys", false, "Enable debug logging and F7 key to set fatigue to 0.5"); LoadIconSprite(); try { Harmony val = new Harmony("jill920.fatiguefromstamina"); val.PatchAll(Assembly.GetExecutingAssembly()); IEnumerable patchedMethods = val.GetPatchedMethods(); foreach (MethodBase item in patchedMethods) { Logger.LogInfo((object)("Patched: " + item.DeclaringType?.Name + "." + item.Name)); } Logger.LogInfo((object)"[Fatigue Mod 1.3.0] Loaded"); Logger.LogInfo((object)$" Exertion Window: {exertionWindowSeconds.Value}s | Max Stamina: {maxStaminaForExertion.Value}"); Logger.LogInfo((object)$" Fatigue Gain: {baseExertionRate.Value} -> {maxExertionRate.Value} per stamina"); Logger.LogInfo((object)$" Fatigue Recovery: {baseRecoveryRate.Value}/s"); } catch (Exception arg) { Logger.LogError((object)$"Harmony patch failed: {arg}"); } } private static void LoadIconSprite() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_0084: 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) try { using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("FatigueMod.Assets.fatigue_icon.png"); if (stream == null) { Logger.LogWarning((object)"Embedded icon not found in resources!"); return; } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; if (ImageConversion.LoadImage(val, memoryStream.ToArray())) { FatigueIconSprite = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)); Logger.LogInfo((object)$"Icon loaded: {((Texture)val).width}x{((Texture)val).height}"); } } catch (Exception arg) { Logger.LogError((object)$"LoadIconSprite failed: {arg}"); } } public static float GetEtcDamageMultiplier() { try { return Ascents.etcDamageMultiplier; } catch { return 1f; } } public static bool IsFatigueDisabled() { return GetEtcDamageMultiplier() <= 0.001f; } public static float GetGainMultiplier() { float etcDamageMultiplier = GetEtcDamageMultiplier(); if (etcDamageMultiplier <= 0.001f) { return 0f; } if (etcDamageMultiplier <= 0.6f) { return 1f; } if (etcDamageMultiplier <= 1.5f) { return 2f; } return 3f; } private void Update() { Character localCharacter = Character.localCharacter; if ((Object)(object)localCharacter != (Object)null && (Object)(object)((Component)localCharacter).GetComponent() == (Object)null) { ((Component)localCharacter).gameObject.AddComponent(); if ((Object)(object)((Component)localCharacter).GetComponent() == (Object)null) { ((Component)localCharacter).gameObject.AddComponent(); } Logger.LogInfo((object)"FatigueTracker attached (fallback)."); } FatigueBarInjector.TryInjectBar(); if (debugMode.Value && !((Object)(object)localCharacter == (Object)null) && Input.GetKeyDown((KeyCode)288)) { FatigueTracker component = ((Component)localCharacter).GetComponent(); if ((Object)(object)component != (Object)null) { component.fatigueValue = 0.5f; Logger.LogInfo((object)"[F7] Forced fatigue = 0.5"); } } } private void OnGUI() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0149: 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_01f5: Unknown result type (might be due to invalid IL or missing references) if (!debugMode.Value) { return; } Character localCharacter = Character.localCharacter; if ((Object)(object)localCharacter == (Object)null) { return; } FatigueTracker component = ((Component)localCharacter).GetComponent(); if (!((Object)(object)component == (Object)null)) { GUIStyle val = new GUIStyle(); val.fontSize = 18; val.normal.textColor = Color.white; float num = 0f; Rigidbody playerRigidbody = FatigueTracker.GetPlayerRigidbody(localCharacter); if ((Object)(object)playerRigidbody != (Object)null) { Vector3 linearVelocity = playerRigidbody.linearVelocity; num = ((Vector3)(ref linearVelocity)).magnitude; } float etcDamageMultiplier = GetEtcDamageMultiplier(); float gainMultiplier = GetGainMultiplier(); string text = (IsFatigueDisabled() ? "DISABLED" : $"x{gainMultiplier:F0}"); float statusSum = localCharacter.refs.afflictions.statusSum; float maxStamina = localCharacter.GetMaxStamina(); float currentStamina = localCharacter.data.currentStamina; GUI.Label(new Rect(20f, 100f, 700f, 30f), $"Speed: {num:F1} Fatigue: {component.fatigueValue:F3} Exertion: {component.CurrentExertionLevel:F2}", val); GUI.Label(new Rect(20f, 122f, 700f, 30f), $"Ground: {component.isGrounded} Climb: {component.isClimbing} RecoveryMult: {component.currentRecoveryMultiplier:F2}x", val); GUI.Label(new Rect(20f, 144f, 700f, 30f), $"FullyOut: {localCharacter.data.fullyPassedOut} Sum: {statusSum:F2} MaxStam: {maxStamina:F2} CurStam: {currentStamina:F2}", val); GUI.Label(new Rect(20f, 166f, 700f, 30f), "CustomBar: " + (((Object)(object)FatigueBarInjector.injectedBar != (Object)null) ? "OK" : "missing"), val); } } } public class FatigueRpcReceiver : MonoBehaviourPun { private Character character; private void Awake() { character = ((Component)this).GetComponent(); } [PunRPC] public void Fatigue_RPC_Sync(float value) { FatigueTracker component = ((Component)this).GetComponent(); if ((Object)(object)component != (Object)null && !component.character.IsLocal) { component.fatigueValue = Mathf.Clamp01(value); } } [PunRPC] public void RPC_ReduceFatigue(float amount) { if (!((MonoBehaviourPun)this).photonView.IsMine) { if (FatiguePlugin.debugMode.Value) { ManualLogSource logger = FatiguePlugin.Logger; Character obj = character; logger.LogInfo((object)("[FATIGUE RPC] Skipping " + ((obj != null) ? obj.characterName : null) + " - not owner")); } } else { if ((Object)(object)character == (Object)null || amount <= 0f) { return; } if (character.data.dead) { if (FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)("[FATIGUE RPC] Skipping " + character.characterName + " - is dead")); } return; } FatigueTracker component = ((Component)this).GetComponent(); if (!((Object)(object)component == (Object)null)) { float fatigueValue = component.fatigueValue; component.fatigueValue = Mathf.Max(0f, component.fatigueValue - amount); if (FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)$"[FATIGUE RPC] {character.characterName}: Fatigue {fatigueValue:F3} -> {component.fatigueValue:F3} (-{amount:F3})"); } } } } private bool IsInvincible() { if ((Object)(object)character == (Object)null || (Object)(object)character.refs?.afflictions == (Object)null) { return false; } Affliction val = default(Affliction); if (character.refs.afflictions.HasAfflictionType((AfflictionType)14, ref val)) { return true; } if (character.refs.afflictions.HasAfflictionType((AfflictionType)16, ref val)) { return true; } return false; } } public class FatigueTracker : MonoBehaviour { public Character character; public float fatigueValue; public float currentRecoveryMultiplier; public bool isGrounded; public bool isClimbing; private float _lastValidStaminaUseTime; private float _playDeadEndTime = 0f; private const float PLAY_DEAD_DURATION = 4f; private float _staminaUsedInWindow; private float _timeAtZeroStamina; private float _zeroStaminaPenalty; private float _lastStaminaCheck; private float _staminaUsageRate; private float _staminaRateSmoothing = 0.2f; private float _lastStaminaTime; private float _lastSyncSent; private const float SYNC_INTERVAL = 0.2f; private float _smoothedVelocity; private float _velocitySmoothing = 0.95f; public bool IsPlayingDead => Time.time < _playDeadEndTime; public float CurrentExertionLevel { get { float num = Mathf.Clamp01(_staminaUsedInWindow / FatiguePlugin.maxStaminaForExertion.Value); float num2 = Mathf.Clamp01((_staminaUsageRate - 30f) / 90f) * 0.6f; return Mathf.Min(1f, num + num2); } } public bool IsResting { get { //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) if (isClimbing) { return false; } if (character.data.isSprinting) { return false; } Rigidbody playerRigidbody = GetPlayerRigidbody(character); if ((Object)(object)playerRigidbody == (Object)null) { return false; } float num = _smoothedVelocity * _velocitySmoothing; Vector3 linearVelocity = playerRigidbody.linearVelocity; _smoothedVelocity = num + ((Vector3)(ref linearVelocity)).magnitude * (1f - _velocitySmoothing); bool flag = _smoothedVelocity < 1.5f; if (FatiguePlugin.debugMode.Value && Time.frameCount % 120 == 0) { FatiguePlugin.Logger.LogInfo((object)$"IsResting: {flag}, Velocity: {_smoothedVelocity:F2}"); } return flag; } } private bool IsInvincible() { if ((Object)(object)character == (Object)null || (Object)(object)character.refs?.afflictions == (Object)null) { return false; } Affliction val = default(Affliction); if (character.refs.afflictions.HasAfflictionType((AfflictionType)14, ref val)) { return true; } if (character.refs.afflictions.HasAfflictionType((AfflictionType)16, ref val)) { return true; } return false; } private float GetBonusStaminaPercentage() { float extraStamina = character.data.extraStamina; float num = Mathf.Clamp01(extraStamina); if (FatiguePlugin.debugMode.Value && Time.frameCount % 300 == 0) { FatiguePlugin.Logger.LogInfo((object)$"Bonus Stamina: {extraStamina:F2} = {num:F2}%"); } return num; } private bool IsImmuneToStaminaDrainFatigue() { if ((Object)(object)character == (Object)null) { return false; } if (IsSkeleton()) { return true; } if (IsInvincible()) { return true; } return false; } private bool IsSkeleton() { if ((Object)(object)character == (Object)null || (Object)(object)character.data == (Object)null) { return false; } if (character.data.isSkeleton && !character.data.dead && !character.data.fullyPassedOut) { return true; } return false; } private void Awake() { character = ((Component)this).GetComponent(); currentRecoveryMultiplier = 1f; _lastStaminaTime = Time.time; _smoothedVelocity = 0f; _lastStaminaCheck = character.data.currentStamina; _timeAtZeroStamina = 0f; _zeroStaminaPenalty = 0f; _lastValidStaminaUseTime = -1f; } public static Rigidbody GetPlayerRigidbody(Character c) { if ((Object)(object)c == (Object)null) { return null; } return ((Component)c).GetComponentInChildren(); } private float GetCurrentMaxStamina() { return Mathf.Max(0f, 1f - character.refs.afflictions.statusSum); } private void UpdateZeroStaminaPenalty() { bool flag = IsTrulyOutOfStamina(); float num = 0.01f; if (flag) { _timeAtZeroStamina += Time.deltaTime; float num2 = Mathf.Clamp01(_timeAtZeroStamina / 4f); _zeroStaminaPenalty = Mathf.MoveTowards(_zeroStaminaPenalty, num2, Time.deltaTime * 2f); bool flag2 = Time.time - _lastValidStaminaUseTime < 0.5f; if (_lastStaminaCheck > num && flag && !IsImmuneToStaminaDrainFatigue() && flag2) { float value = FatiguePlugin.zeroStaminaFatigue.Value; fatigueValue = Mathf.Min(1f, fatigueValue + value); if (FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)($"STAMINA ZERO (Primary + Bonus)! +{value:F3} fatigue (total: {fatigueValue:F3}) | " + $"Last valid use: {Time.time - _lastValidStaminaUseTime:F2}s ago")); } } else if (_lastStaminaCheck > num && flag && !flag2 && FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)"STAMINA ZERO but from NON-MOVEMENT action - No fatigue penalty applied"); } else if (_lastStaminaCheck > num && flag && IsImmuneToStaminaDrainFatigue() && FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)"STAMINA ZERO but IMMUNE - No fatigue penalty applied"); } } else if (_zeroStaminaPenalty > 0f) { float num3 = 1f; _zeroStaminaPenalty = Mathf.MoveTowards(_zeroStaminaPenalty, 0f, Time.deltaTime * num3); _timeAtZeroStamina = Mathf.MoveTowards(_timeAtZeroStamina, 0f, Time.deltaTime); } _lastStaminaCheck = character.data.currentStamina + character.data.extraStamina; if (FatiguePlugin.debugMode.Value && _zeroStaminaPenalty > 0.01f && Time.frameCount % 60 == 0) { FatiguePlugin.Logger.LogInfo((object)$"Zero stamina penalty: {_zeroStaminaPenalty:F2} (time at zero: {_timeAtZeroStamina:F1}s)"); } } public void OnStaminaUsed(float usage) { if (usage <= 0f) { return; } float time = Time.time; float num = time - _lastStaminaTime; bool flag = character.data.isClimbing || character.data.isRopeClimbing || character.data.isVineClimbing; bool flag2 = false; string text = "UNKNOWN"; if (character.data.isSprinting) { flag2 = true; text = "SPRINT"; } else if (flag) { flag2 = true; text = "CLIMB"; } else if (character.data.sinceJump < 0.1f) { flag2 = true; text = "JUMP"; } else if (character.data.isGrounded && ((Vector3)(ref character.data.worldMovementInput)).magnitude > 0.5f) { flag2 = false; text = "MOVE"; } else { text = "OTHER"; } if (flag2) { _lastValidStaminaUseTime = time; } bool flag3 = character.data.currentStamina <= 0.01f && character.data.extraStamina > 0f; bool flag4 = character.data.currentStamina > 0.01f; float bonusStaminaPercentage = GetBonusStaminaPercentage(); float num2 = 1f; string text2 = "PRIMARY"; if (flag3) { num2 = Mathf.Lerp(1f, 0.6f, bonusStaminaPercentage); text2 = (flag ? "BONUS_CLIMB" : "BONUS"); } else if (flag4) { num2 = Mathf.Lerp(1f, 0.6f, bonusStaminaPercentage); text2 = (flag ? "PRIMARY_CLIMB" : "PRIMARY"); } float num3 = num2; num3 = Mathf.Clamp(num3, 0.35f, 1.2f); float num4 = usage / Mathf.Max(0.016f, num); _staminaUsageRate = Mathf.Lerp(_staminaUsageRate, num4, _staminaRateSmoothing); float num5 = usage * num3; _staminaUsedInWindow += num5; _lastStaminaTime = time; if (FatiguePlugin.debugMode.Value && usage > 0.01f) { FatiguePlugin.Logger.LogInfo((object)($"Stamina used: {usage:F2} ({text2}, action: {text}, valid: {flag2}, mult: {num3:F2}, climbing: {flag}, bonus%: {bonusStaminaPercentage:F2}) | " + $"Primary: {character.data.currentStamina:F2}, Bonus: {character.data.extraStamina:F2} | " + $"Rate: {_staminaUsageRate:F0}/s | Window total: {_staminaUsedInWindow:F1}/{FatiguePlugin.maxStaminaForExertion.Value:F0}")); } if (!IsInvincible() && !IsSkeleton() && !FatigueAfflictionHandler.IsFatigueBlocked(character) && !IsImmuneToStaminaDrainFatigue()) { float num6 = Mathf.Lerp(FatiguePlugin.baseExertionRate.Value, FatiguePlugin.maxExertionRate.Value, CurrentExertionLevel); float num7 = usage * num6 * num3 * FatiguePlugin.GetGainMultiplier(); if (num7 > 0f) { fatigueValue = Mathf.Min(1f, fatigueValue + num7); if (FatiguePlugin.debugMode.Value && num7 > 0.001f) { FatiguePlugin.Logger.LogInfo((object)($" -> Fatigue +{num7:F4} (total: {fatigueValue:F3}) | " + $"Exertion: {CurrentExertionLevel:F2} | Rate: {num6:F3} | " + $"Source: {text2} (base: {num2:F2}, final: {num3:F2})")); } } } else if (FatiguePlugin.debugMode.Value && (IsInvincible() || IsSkeleton() || IsImmuneToStaminaDrainFatigue())) { FatiguePlugin.Logger.LogInfo((object)"Fatigue gain blocked by immunity"); } } public void SetPlayingDead(bool playing) { if (playing) { _playDeadEndTime = Time.time + 4f; if (FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)"Play Dead emote started - Fatigue recovery boosted"); } } else { _playDeadEndTime = 0f; if (FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)"Play Dead emote ended"); } } } private void UpdateStaminaWindow() { float num = Time.time - _lastStaminaTime; if (num > 0.5f) { float num2 = FatiguePlugin.maxStaminaForExertion.Value / FatiguePlugin.exertionWindowSeconds.Value; float num3 = Time.deltaTime * num2; _staminaUsedInWindow = Mathf.Max(0f, _staminaUsedInWindow - num3); } if (num > 1f) { _staminaUsageRate = Mathf.MoveTowards(_staminaUsageRate, 0f, Time.deltaTime * 20f); } } private float GetStaminaPercentage() { float currentMaxStamina = GetCurrentMaxStamina(); if (currentMaxStamina <= 0f) { return 0f; } float num = character.data.currentStamina + character.data.extraStamina; return Mathf.Clamp01(num / currentMaxStamina); } private bool IsTrulyOutOfStamina() { return character.data.currentStamina <= 0.01f && character.data.extraStamina <= 0.01f; } private float CalculateRecoveryMultiplier() { if (character.data.passedOut || character.data.fullyPassedOut) { return 1f; } float num = 1f; float num2 = Mathf.Clamp01(CurrentExertionLevel) * 1f; num -= num2; float staminaDeficitPenalty = GetStaminaDeficitPenalty(); if (!float.IsNaN(staminaDeficitPenalty) && !float.IsInfinity(staminaDeficitPenalty)) { num -= staminaDeficitPenalty * 0.3f; } float num3 = Mathf.Clamp01(_zeroStaminaPenalty) * 0.8f; num -= num3; if (IsResting) { num += 0.15f; } num = Mathf.Clamp(num, 0f, 1f); if (IsPlayingDead && !float.IsNaN(num)) { num *= 1.66f; } if (float.IsNaN(num) || float.IsInfinity(num)) { num = 1f; } return num; } private float GetCurrentRecoveryRate() { float num = CalculateRecoveryMultiplier(); float num2 = FatiguePlugin.baseRecoveryRate.Value * num; if (character.data.passedOut || character.data.fullyPassedOut) { num2 = Mathf.Max(num2, FatiguePlugin.baseRecoveryRate.Value); } return num2; } private float GetStaminaDeficitPenalty() { float num = Mathf.Clamp01(GetStaminaPercentage()); float num2 = Mathf.Pow(1f - num, 1.5f) * 0.95f; return Mathf.Clamp01(num2); } private void Update() { if ((Object)(object)character == (Object)null || !character.IsLocal) { return; } isGrounded = character.data.isGrounded; isClimbing = character.data.isClimbing || character.data.isRopeClimbing || character.data.isVineClimbing; if (!character.data.passedOut && !character.data.fullyPassedOut) { UpdateZeroStaminaPenalty(); UpdateStaminaWindow(); } else { _zeroStaminaPenalty = Mathf.MoveTowards(_zeroStaminaPenalty, 0f, Time.deltaTime); } float num = (currentRecoveryMultiplier = CalculateRecoveryMultiplier()); if (!IsSkeleton() && fatigueValue > 0f) { float num2 = FatiguePlugin.baseRecoveryRate.Value * num; if (character.data.passedOut || character.data.fullyPassedOut) { num2 = Mathf.Max(num2, FatiguePlugin.baseRecoveryRate.Value); } if (num2 > 0f) { float num3 = fatigueValue; float num4 = num2 * Time.deltaTime; fatigueValue = Mathf.Max(0f, fatigueValue - num4); if (FatiguePlugin.debugMode.Value && num4 > 0.0005f && Time.frameCount % 60 == 0) { FatiguePlugin.Logger.LogInfo((object)$"Recovery: {num4:F4}/s | Fatigue: {num3:F3} -> {fatigueValue:F3}"); } } } MaybeSendSync(); } private void MaybeSendSync() { if (Time.time - _lastSyncSent < 0.2f) { return; } _lastSyncSent = Time.time; PhotonView component = ((Component)character).GetComponent(); if ((Object)(object)component == (Object)null || !PhotonNetwork.InRoom) { return; } try { component.RPC("Fatigue_RPC_Sync", (RpcTarget)1, new object[1] { fatigueValue }); } catch (Exception ex) { FatiguePlugin.Logger.LogWarning((object)("RPC send failed: " + ex.Message)); } } } } namespace FatigueMod.Patches { [HarmonyPatch(typeof(AOE), "Explode")] internal static class AOE_CureAll_Patch { private static FieldInfo hasExplodedField; private static bool isProcessing; static AOE_CureAll_Patch() { isProcessing = false; hasExplodedField = typeof(AOE).GetField("hasExploded", BindingFlags.Instance | BindingFlags.NonPublic); } [HarmonyPrefix] private static bool Prefix(AOE __instance) { //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) if (isProcessing) { return true; } if (hasExplodedField != null && (bool)hasExplodedField.GetValue(__instance)) { return true; } if (!((Object)__instance).name.Contains("CureAll") && !((Object)__instance).name.Contains("AOE_CureAll")) { return true; } if (FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)("[CUREALL AOE] Processing " + ((Object)__instance).name)); } isProcessing = true; try { if (hasExplodedField != null) { hasExplodedField.SetValue(__instance, true); } float statusAmount = __instance.statusAmount; STATUSTYPE statusType = __instance.statusType; STATUSTYPE[] addtlStatus = __instance.addtlStatus; bool hasAffliction = __instance.hasAffliction; Affliction affliction = __instance.affliction; __instance.statusAmount = 0f; __instance.hasAffliction = false; __instance.affliction = null; __instance.statusAmount = statusAmount; __instance.hasAffliction = hasAffliction; __instance.affliction = affliction; return true; } finally { isProcessing = false; } } [HarmonyPostfix] private static void Postfix(AOE __instance) { //IL_00d0: 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) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_035a: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Unknown result type (might be due to invalid IL or missing references) //IL_036d: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Unknown result type (might be due to invalid IL or missing references) if (isProcessing || (!((Object)__instance).name.Contains("CureAll") && !((Object)__instance).name.Contains("AOE_CureAll"))) { return; } if (!PhotonNetwork.IsMasterClient) { if (FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)"[CUREALL AOE] Skipping fatigue reduction - not MasterClient"); } return; } if (FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)"[CUREALL AOE] Postfix - applying fatigue reduction to characters in range"); FatiguePlugin.Logger.LogInfo((object)$"[CUREALL AOE] Position: {((Component)__instance).transform.position}, Range: {__instance.range}"); } Collider[] array = Physics.OverlapSphere(((Component)__instance).transform.position, __instance.range, LayerMask.op_Implicit(HelperFunctions.GetMask(__instance.mask))); List list = new List(); Collider[] array2 = array; Character item = default(Character); Character val2 = default(Character); foreach (Collider val in array2) { if (CharacterRagdoll.TryGetCharacterFromCollider(val, ref item) && !list.Contains(item)) { list.Add(item); } if (CharacterRagdoll.TryGetCharacterFromCollider(val, ref val2) && (Object)(object)val2.data.carriedPlayer != (Object)null && !list.Contains(val2.data.carriedPlayer)) { list.Add(val2.data.carriedPlayer); if (FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)("[CUREALL AOE] Found carried player " + val2.data.carriedPlayer.characterName)); } } } if (FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)$"[CUREALL AOE] Found {list.Count} characters in range"); foreach (Character item2 in list) { FatiguePlugin.Logger.LogInfo((object)$"[CUREALL AOE] - {item2.characterName} (IsDead: {item2.data.dead}, IsSkeleton: {item2.data.isSkeleton})"); } } foreach (Character item3 in list) { if (item3.data.dead || item3.data.fullyPassedOut) { if (FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)("[CUREALL AOE] Skipping " + item3.characterName + " - dead or passed out")); } continue; } float num = Vector3.Distance(((Component)__instance).transform.position, item3.Center); if (num > __instance.range) { continue; } float num2 = Mathf.Pow(1f - num / __instance.range, __instance.factorPow); if (num2 < __instance.minFactor) { continue; } if (__instance.requireLineOfSigh) { RaycastHit val3 = HelperFunctions.LineCheck(((Component)__instance).transform.position, item3.Center, (LayerType)1, 0f, (QueryTriggerInteraction)1); if (Object.op_Implicit((Object)(object)((RaycastHit)(ref val3)).transform)) { continue; } } float num3 = 0.1f * num2; FatigueRpcReceiver component = ((Component)item3).GetComponent(); if ((Object)(object)component != (Object)null) { ((MonoBehaviourPun)component).photonView.RPC("RPC_ReduceFatigue", ((MonoBehaviourPun)component).photonView.Owner, new object[1] { num3 }); if (FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)$"[CUREALL AOE] Sent fatigue reduction RPC to {item3.characterName}: -{num3:F3} fatigue"); } } else { FatiguePlugin.Logger.LogWarning((object)("[CUREALL AOE] No FatigueRpcReceiver on " + item3.characterName)); } } } } [HarmonyPatch(typeof(CharacterAnimations), "PlayEmote")] internal static class CharacterAnimations_PlayEmote_Patch { private static Coroutine activeResetCoroutine; [HarmonyPrefix] private static void Prefix(CharacterAnimations __instance, string emoteName) { Character component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsLocal) { return; } FatigueTracker component2 = ((Component)component).GetComponent(); if ((Object)(object)component2 == (Object)null || !(emoteName == "A_Scout_Emote_PlayDead")) { return; } if (activeResetCoroutine != null) { ((MonoBehaviour)__instance).StopCoroutine(activeResetCoroutine); if (FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)"Previous Play Dead reset coroutine cancelled - duration refreshed"); } } component2.SetPlayingDead(playing: true); activeResetCoroutine = ((MonoBehaviour)__instance).StartCoroutine(ResetPlayDeadAfterDelay(component2, 5f, __instance)); } private static IEnumerator ResetPlayDeadAfterDelay(FatigueTracker tracker, float delay, CharacterAnimations animator) { yield return (object)new WaitForSeconds(delay); if ((Object)(object)tracker != (Object)null && tracker.IsPlayingDead) { tracker.SetPlayingDead(playing: false); activeResetCoroutine = null; if (FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)"Play Dead emote timeout - resetting recovery rate"); } } } } [HarmonyPatch(typeof(EmoteWheel), "Choose")] internal static class EmoteWheel_Choose_Patch { [HarmonyPrefix] private static void Prefix(EmoteWheel __instance) { FieldInfo field = typeof(EmoteWheel).GetField("chosenEmoteData", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { return; } object? value = field.GetValue(__instance); EmoteWheelData val = (EmoteWheelData)((value is EmoteWheelData) ? value : null); if ((Object)(object)val == (Object)null || !(val.anim == "A_Scout_Emote_PlayDead")) { return; } Character localCharacter = Character.localCharacter; if ((Object)(object)localCharacter == (Object)null) { return; } FatigueTracker component = ((Component)localCharacter).GetComponent(); if (!((Object)(object)component == (Object)null)) { component.SetPlayingDead(playing: true); if (FatiguePlugin.debugMode.Value) { FatiguePlugin.Logger.LogInfo((object)"Play Dead emote detected via EmoteWheel.Choose()"); } } } } }