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 Better Stamina v2.1.1
BetterStamina.dll
Decompiled 2 years agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BetterStamina; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("BetterStamina")] [assembly: AssemblyDescription("Rebalances stamina system to make it more forgiving and improve the combat flow.")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("BetterStamina")] [assembly: AssemblyCopyright("Copyright © bakaspaceman 2021-2023")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("c78b697c-0617-40b5-b559-88d31b5ed1a8")] [assembly: AssemblyFileVersion("2.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyVersion("2.0.0.0")] internal static class StatusEffectPatches { private static void UpdateStatusEffect(StatusEffect se, bool onPlayer = false) { string text = (onPlayer ? " on local player " : " in ObjectDB "); SE_Stats val = (SE_Stats)(object)((se is SE_Stats) ? se : null); if (val != null) { switch (se.m_name) { case "$se_cold_name": BepInPluginTemplate.DebugLog($"[{Localization.instance.Localize(se.m_name)}] Updating m_staminaRegenMultiplier{text}from {val.m_staminaRegenMultiplier} to {BetterStaminaPlugin.coldStaminaRegenMultiplier.Value}"); val.m_staminaRegenMultiplier = BetterStaminaPlugin.coldStaminaRegenMultiplier.Value; break; case "$se_wet_name": BepInPluginTemplate.DebugLog($"[{Localization.instance.Localize(se.m_name)}] Updating m_staminaRegenMultiplier{text}from {val.m_staminaRegenMultiplier} to {BetterStaminaPlugin.wetStaminaRegenMultiplier.Value}"); val.m_staminaRegenMultiplier = BetterStaminaPlugin.wetStaminaRegenMultiplier.Value; break; case "$se_rested_name": { BepInPluginTemplate.DebugLog($"[{Localization.instance.Localize(se.m_name)}] Updating m_staminaRegenMultiplier{text}from {val.m_staminaRegenMultiplier} to {BetterStaminaPlugin.restedStaminaRegenMultiplier.Value}"); val.m_staminaRegenMultiplier = BetterStaminaPlugin.restedStaminaRegenMultiplier.Value; SE_Rested val2 = (SE_Rested)(object)((se is SE_Rested) ? se : null); BepInPluginTemplate.DebugLog($"[{Localization.instance.Localize(se.m_name)}] Updating m_TTLPerComfortLevel{text}from {val2.m_TTLPerComfortLevel} to {BetterStaminaPlugin.restedDurationPerComfortLvl.Value}"); val2.m_TTLPerComfortLevel = BetterStaminaPlugin.restedDurationPerComfortLvl.Value; break; } } } } public static void UpdateEffects(ObjectDB __instance) { foreach (StatusEffect statusEffect in __instance.m_StatusEffects) { if (statusEffect is SE_Stats) { UpdateStatusEffect(statusEffect); } } } [HarmonyPatch(typeof(ObjectDB), "Awake")] [HarmonyPostfix] public static void ObjectDBAwake_PostFix(ObjectDB __instance) { UpdateEffects(__instance); } [HarmonyPatch(typeof(Player), "SetLocalPlayer")] [HarmonyPostfix] public static void SetLocalPlayerPostFix(Player __instance, SEMan ___m_seman) { if (!((Object)(object)__instance != (Object)null) || ___m_seman == null) { return; } foreach (StatusEffect item in (List<StatusEffect>)BetterStaminaPlugin.statusEffectsField.GetValue(___m_seman)) { UpdateStatusEffect(item, onPlayer: true); } } } internal static class SkillPatches { private static float defaultBlockStaminaDrain; private static float defaultSneakStaminaDrain; private static float defaultStaminaUsage; private static float defaultJumpStaminaUsage; [HarmonyPatch(typeof(Player), "OnSneaking")] [HarmonyPrefix] private static void OnSneaking_Prefix(Player __instance, Skills ___m_skills) { defaultSneakStaminaDrain = __instance.m_sneakStaminaDrain; if (!((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)Player.m_localPlayer != (Object)(object)__instance)) { float num = EasingFunctions.GetEasingFunction(EasingFunctions.Ease.EaseOutSine)(1f, BetterStaminaPlugin.sneakMaxSkillStaminaCost.Value, ___m_skills.GetSkillFactor((SkillType)100)); __instance.m_sneakStaminaDrain *= num; if (BetterStaminaPlugin.enableSkillStaminaLogging != null && BetterStaminaPlugin.enableSkillStaminaLogging.Value) { BepInPluginTemplate.DebugLog($"OnSneaking: Usage change: {defaultSneakStaminaDrain} - {__instance.m_sneakStaminaDrain}; Mathf.Lerp: {Mathf.Lerp(1f, BetterStaminaPlugin.sneakMaxSkillStaminaCost.Value, ___m_skills.GetSkillFactor((SkillType)100))}; Custom: {num}; skill: {___m_skills.GetSkillFactor((SkillType)100)};"); } } } [HarmonyPatch(typeof(Player), "OnSneaking")] [HarmonyPostfix] private static void OnSneaking_PostFix(Player __instance) { if (defaultSneakStaminaDrain != 0f) { __instance.m_sneakStaminaDrain = defaultSneakStaminaDrain; } } [HarmonyPatch(typeof(Player), "OnJump")] [HarmonyPrefix] private static void OnJump_Prefix(Player __instance, Skills ___m_skills) { defaultJumpStaminaUsage = ((Character)__instance).m_jumpStaminaUsage; if (!((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)Player.m_localPlayer != (Object)(object)__instance)) { float num = EasingFunctions.GetEasingFunction(EasingFunctions.Ease.EaseOutSine)(1f, BetterStaminaPlugin.jumpMaxSkillStaminaCost.Value, ___m_skills.GetSkillFactor((SkillType)100)); ((Character)__instance).m_jumpStaminaUsage = ((Character)__instance).m_jumpStaminaUsage * num; if (BetterStaminaPlugin.enableSkillStaminaLogging != null && BetterStaminaPlugin.enableSkillStaminaLogging.Value) { BepInPluginTemplate.DebugLog($"OnJump: Usage change: {defaultJumpStaminaUsage} - {((Character)__instance).m_jumpStaminaUsage}; Mathf.Lerp: {Mathf.Lerp(1f, BetterStaminaPlugin.jumpMaxSkillStaminaCost.Value, ___m_skills.GetSkillFactor((SkillType)100))}; Custom: {num}; skill: {___m_skills.GetSkillFactor((SkillType)100)};"); } } } [HarmonyPatch(typeof(Player), "OnJump")] [HarmonyPostfix] private static void OnJump_PostFix(Player __instance) { if (defaultJumpStaminaUsage != 0f) { ((Character)__instance).m_jumpStaminaUsage = defaultJumpStaminaUsage; } } [HarmonyPatch(typeof(Player), "UpdateDodge")] [HarmonyPrefix] private static void UpdateDodge_Prefix(Player __instance, Skills ___m_skills, float ___m_queuedDodgeTimer) { defaultStaminaUsage = __instance.m_dodgeStaminaUsage; if (!((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)Player.m_localPlayer != (Object)(object)__instance)) { float num = EasingFunctions.GetEasingFunction(EasingFunctions.Ease.EaseOutSine)(1f, BetterStaminaPlugin.dodgeMaxSkillStaminaCost.Value, ___m_skills.GetSkillFactor((SkillType)100)); __instance.m_dodgeStaminaUsage *= num; if (BetterStaminaPlugin.enableSkillStaminaLogging != null && BetterStaminaPlugin.enableSkillStaminaLogging.Value && (double)___m_queuedDodgeTimer > 0.0 && ((Character)__instance).IsOnGround() && !((Character)__instance).IsDead() && !((Character)__instance).InAttack() && !((Character)__instance).IsEncumbered() && !((Character)__instance).InDodge()) { BepInPluginTemplate.DebugLog($"UpdateDoge: Usage change: {defaultStaminaUsage} - {__instance.m_dodgeStaminaUsage}; Mathf.Lerp: {Mathf.Lerp(1f, BetterStaminaPlugin.dodgeMaxSkillStaminaCost.Value, ___m_skills.GetSkillFactor((SkillType)100))}; Custom: {num}; skill: {___m_skills.GetSkillFactor((SkillType)100)};"); } } } [HarmonyPatch(typeof(Player), "UpdateDodge")] [HarmonyPostfix] private static void UpdateDodge_PostFix(Player __instance) { if (defaultStaminaUsage != 0f) { __instance.m_dodgeStaminaUsage = defaultStaminaUsage; } } [HarmonyPatch(typeof(Humanoid), "BlockAttack")] [HarmonyPrefix] private static void BlockAttack_Prefix(Humanoid __instance) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown if (!((Object)(object)Player.m_localPlayer != (Object)null) || !((Object)(object)Player.m_localPlayer == (Object)(object)__instance)) { return; } defaultBlockStaminaDrain = __instance.m_blockStaminaDrain; Skills val = (Skills)BetterStaminaPlugin.playerSkillsField.GetValue(Player.m_localPlayer); if (!((Object)(object)val == (Object)null)) { float num = EasingFunctions.GetEasingFunction(EasingFunctions.Ease.EaseOutSine)(1f, BetterStaminaPlugin.blockMaxSkillStaminaCost.Value, val.GetSkillFactor((SkillType)6)); __instance.m_blockStaminaDrain *= num; if (BetterStaminaPlugin.enableSkillStaminaLogging != null && BetterStaminaPlugin.enableSkillStaminaLogging.Value) { BepInPluginTemplate.DebugLog($"BlockAttack: Usage change: {defaultBlockStaminaDrain} - {__instance.m_blockStaminaDrain}; Mathf.Lerp: {Mathf.Lerp(1f, BetterStaminaPlugin.blockMaxSkillStaminaCost.Value, val.GetSkillFactor((SkillType)6))}; Custom: {num}; skill: {val.GetSkillFactor((SkillType)6)};"); } } } [HarmonyPatch(typeof(Humanoid), "BlockAttack")] [HarmonyPostfix] private static void BlockAttack_PostFix(Player __instance) { if (defaultBlockStaminaDrain != 0f) { ((Humanoid)__instance).m_blockStaminaDrain = defaultBlockStaminaDrain; } } [HarmonyPatch(typeof(Attack), "GetAttackStamina")] [HarmonyPrefix] private static bool GetStaminaUsage_Prefix(Attack __instance, Humanoid ___m_character, float ___m_attackStamina, ItemData ___m_weapon, ref float __result) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)Player.m_localPlayer != (Object)(object)___m_character) { return true; } if ((double)___m_attackStamina <= 0.0) { __result = 0f; return false; } double num = ___m_attackStamina; float num2 = EasingFunctions.GetEasingFunction(EasingFunctions.Ease.EaseOutSine)(1f, BetterStaminaPlugin.weaponMaxSkillAttackStaminaCost.Value, ((Character)___m_character).GetSkillFactor(___m_weapon.m_shared.m_skillType)); __result = (float)(num * (double)num2); if (BetterStaminaPlugin.enableSkillStaminaLogging != null && BetterStaminaPlugin.enableSkillStaminaLogging.Value && new StackFrame(2).GetMethod().Name.Contains("Update")) { float num3 = (float)(num * (double)(1f - BetterStaminaPlugin.weaponMaxSkillAttackStaminaCost.Value) * (double)((Character)___m_character).GetSkillFactor(___m_weapon.m_shared.m_skillType)); float num4 = (float)(num - (double)num3); BepInPluginTemplate.DebugLog($"Attack.GetStaminaUsage(): Cost - {__result}; Original: {num4}; Custom: {__result}; skill: {((Character)___m_character).GetSkillFactor(___m_weapon.m_shared.m_skillType)}({___m_weapon.m_shared.m_skillType});"); } return false; } [HarmonyPatch(typeof(ItemData), "GetDrawStaminaDrain")] [HarmonyPostfix] private static void GetDrawStaminaDrain_Postfix(SharedData ___m_shared, ref float __result) { //IL_0028: 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_00af: Unknown result type (might be due to invalid IL or missing references) float drawStaminaDrain = ___m_shared.m_attack.m_drawStaminaDrain; float num = EasingFunctions.GetEasingFunction(EasingFunctions.Ease.EaseOutSine)(1f, BetterStaminaPlugin.bowMaxSkillHoldStaminaCost.Value, ((Character)Player.m_localPlayer).GetSkillFactor(___m_shared.m_skillType)); float num2 = (__result = drawStaminaDrain * num); if (BetterStaminaPlugin.enableSkillStaminaLogging != null && BetterStaminaPlugin.enableSkillStaminaLogging.Value) { BepInPluginTemplate.DebugLog($"BowHoldStamina: Usage change: {drawStaminaDrain} - {num2}; Mathf.Lerp: {Mathf.Lerp(1f, BetterStaminaPlugin.bowMaxSkillHoldStaminaCost.Value, ((Character)Player.m_localPlayer).GetSkillFactor(___m_shared.m_skillType))}; Custom: {num}; skill: {((Character)Player.m_localPlayer).GetSkillFactor(___m_shared.m_skillType)};"); } } public static float GetRunStaminaSkillFactor(float drainMax, float drainMin, float skillFactor, Player playerInst) { drainMin = BetterStaminaPlugin.runMaxSkillStaminaCost.Value; if ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)Player.m_localPlayer == (Object)(object)playerInst) { if (((Humanoid)playerInst).GetCurrentWeapon() != null && !((object)((Humanoid)playerInst).GetCurrentWeapon()).Equals((object?)((Humanoid)playerInst).m_unarmedWeapon.m_itemData)) { drainMin = BetterStaminaPlugin.runWithWeapMaxSkillStaminaCost.Value; } float num = EasingFunctions.GetEasingFunction(EasingFunctions.Ease.EaseOutSine)(drainMax, drainMin, skillFactor); if (BetterStaminaPlugin.enableSkillStaminaLogging != null && BetterStaminaPlugin.enableSkillStaminaLogging.Value) { BepInPluginTemplate.DebugLog($"RunStamina: Skill factor change: {Mathf.Lerp(drainMax, drainMin, skillFactor)} - {num}"); } return num; } return Mathf.Lerp(drainMax, drainMin, skillFactor); } [HarmonyPatch(typeof(Player), "CheckRun")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> CheckRun_Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Expected O, but got Unknown BepInPluginTemplate.DebugTranspilerLog("######## CheckRun_Transpiler START ########"); List<CodeInstruction> list = new List<CodeInstruction>(instructions); for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; BepInPluginTemplate.DebugTranspilerLog($"{i} {val}"); if (val.opcode == OpCodes.Call && ((object)val).ToString().Contains("Mathf::Lerp")) { int num = i; BepInPluginTemplate.DebugTranspilerLog($">>> Deleting instruction {num} {((object)list[num]).ToString()}:"); list.RemoveAt(i); BepInPluginTemplate.DebugTranspilerLog($">>> Inserting instruction at {num}:"); BepInPluginTemplate.DebugTranspilerLog("Old: " + ((object)list[num]).ToString()); list.Insert(num, new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(SkillPatches), "GetRunStaminaSkillFactor", (Type[])null, (Type[])null))); BepInPluginTemplate.DebugTranspilerLog("New: " + ((object)list[num]).ToString()); BepInPluginTemplate.DebugTranspilerLog($">>> Inserting instruction at {num}:"); BepInPluginTemplate.DebugTranspilerLog("Old: " + ((object)list[num]).ToString()); list.Insert(num, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); BepInPluginTemplate.DebugTranspilerLog("New: " + ((object)list[num]).ToString()); break; } } BepInPluginTemplate.DebugTranspilerLog(""); BepInPluginTemplate.DebugTranspilerLog("#############################################################"); BepInPluginTemplate.DebugTranspilerLog($"######## MODIFIED INSTRUCTIONS - {list.Count} ########"); BepInPluginTemplate.DebugTranspilerLog("#############################################################"); BepInPluginTemplate.DebugTranspilerLog(""); for (int j = 0; j < list.Count; j++) { CodeInstruction arg = list[j]; BepInPluginTemplate.DebugTranspilerLog($"{j} {arg}"); } BepInPluginTemplate.DebugTranspilerLog("######## CheckRun_Transpiler END ########"); BepInPluginTemplate.DebugTranspilerLog(""); return list; } public static float GetSwimmingStaminaDrain(float drainMax, float drainMin, float skillFactor, Player playerInst) { if ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)Player.m_localPlayer == (Object)(object)playerInst) { float num = EasingFunctions.GetEasingFunction(EasingFunctions.Ease.EaseOutSine)(BetterStaminaPlugin.swimMaxStaminaCost.Value, BetterStaminaPlugin.swimMinStaminaCost.Value, skillFactor); if (BetterStaminaPlugin.enableSkillStaminaLogging != null && BetterStaminaPlugin.enableSkillStaminaLogging.Value) { BepInPluginTemplate.DebugLog($"SwimStamina: Usage change: {Mathf.Lerp(drainMax, drainMin, skillFactor)} - {num}; skill: {((Character)playerInst).GetSkillFactor((SkillType)103)};"); } return num; } return Mathf.Lerp(drainMax, drainMin, skillFactor); } [HarmonyPatch(typeof(Player), "OnSwimming")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> OnSwimming_Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Expected O, but got Unknown BepInPluginTemplate.DebugTranspilerLog("######## OnSwimming_Transpiler START ########"); List<CodeInstruction> list = new List<CodeInstruction>(instructions); for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; BepInPluginTemplate.DebugTranspilerLog($"{i} {val}"); if (val.opcode == OpCodes.Call && ((object)val).ToString().Contains("Mathf::Lerp")) { int num = i; BepInPluginTemplate.DebugTranspilerLog($">>> Deleting instruction {num} {((object)list[num]).ToString()}:"); list.RemoveAt(i); BepInPluginTemplate.DebugTranspilerLog($">>> Inserting instruction at {num}:"); BepInPluginTemplate.DebugTranspilerLog("Old: " + ((object)list[num]).ToString()); list.Insert(num, new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(SkillPatches), "GetSwimmingStaminaDrain", (Type[])null, (Type[])null))); BepInPluginTemplate.DebugTranspilerLog("New: " + ((object)list[num]).ToString()); BepInPluginTemplate.DebugTranspilerLog($">>> Inserting instruction at {num}:"); BepInPluginTemplate.DebugTranspilerLog("Old: " + ((object)list[num]).ToString()); list.Insert(num, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); BepInPluginTemplate.DebugTranspilerLog("New: " + ((object)list[num]).ToString()); break; } } BepInPluginTemplate.DebugTranspilerLog(""); BepInPluginTemplate.DebugTranspilerLog("#############################################################"); BepInPluginTemplate.DebugTranspilerLog($"######## MODIFIED INSTRUCTIONS - {list.Count} ########"); BepInPluginTemplate.DebugTranspilerLog("#############################################################"); BepInPluginTemplate.DebugTranspilerLog(""); for (int j = 0; j < list.Count; j++) { CodeInstruction arg = list[j]; BepInPluginTemplate.DebugTranspilerLog($"{j} {arg}"); } BepInPluginTemplate.DebugTranspilerLog("######## OnSwimming_Transpiler END ########"); BepInPluginTemplate.DebugTranspilerLog(""); return list; } } internal static class GeneralStaminaPatches { private static float defaultEncumberedStaminaDrain; private static void UpdateEncumberedStaminaDrain(Player __instance) { if (BetterStaminaPlugin.removeEncumberedStaminaDrain.Value) { if (defaultEncumberedStaminaDrain == 0f) { defaultEncumberedStaminaDrain = __instance.m_encumberedStaminaDrain; } __instance.m_encumberedStaminaDrain = 0f; } else if (defaultEncumberedStaminaDrain != 0f) { __instance.m_encumberedStaminaDrain = defaultEncumberedStaminaDrain; defaultEncumberedStaminaDrain = 0f; } } private static float CalculateNewStamina(Player __instance, bool ___m_wallRunning, float ___m_staminaRegen, float ___m_stamina, SEMan ___m_seman, ref float ___m_staminaRegenTimer, float dt) { float num = 1f; if (((Character)__instance).IsBlocking()) { num *= 0.8f; } if (((((Character)__instance).IsSwimming() && !((Character)__instance).IsOnGround()) || ((Character)__instance).InAttack() || ((Character)__instance).InDodge() || ___m_wallRunning) | ((Character)__instance).IsEncumbered()) { num = 0f; } float maxStamina = ((Character)__instance).GetMaxStamina(); float num2 = (float)(1.0 - (double)___m_stamina / (double)maxStamina); float num3 = (___m_staminaRegen + num2 * ___m_staminaRegen * __instance.m_staminaRegenTimeMultiplier) * num; float num4 = 1f; ___m_seman.ModifyStaminaRegen(ref num4); float num5 = num3 * num4; ___m_staminaRegenTimer -= dt; float num6 = ___m_stamina; if ((double)___m_stamina < (double)maxStamina && (double)___m_staminaRegenTimer <= 0.0) { num6 = Mathf.Min(maxStamina, ___m_stamina + num5 * dt); } float num7 = num6 - ___m_stamina; if (Mathf.Abs(num7) > 0f) { BepInPluginTemplate.DebugLog($"StaminaChangeThisFrame: {num5}(dt-{num7}), base regen - {___m_staminaRegen}; activity mult - {num}; base mult - {__instance.m_staminaRegenTimeMultiplier}; missing mult - {num2}; SE mult - {num4}"); } return num6; } [HarmonyPatch(typeof(Player), "UpdateStats", new Type[] { typeof(float) })] [HarmonyPrefix] private static void UpdateStats_Prefix(Player __instance, float dt, SEMan ___m_seman, bool ___m_wallRunning, float ___m_staminaRegen, float ___m_stamina, float ___m_staminaRegenTimer) { UpdateEncumberedStaminaDrain(__instance); __instance.m_staminaRegenTimeMultiplier = ((((Humanoid)__instance).GetCurrentWeapon() != null && !((object)((Humanoid)__instance).GetCurrentWeapon()).Equals((object?)((Humanoid)__instance).m_unarmedWeapon.m_itemData)) ? BetterStaminaPlugin.staminaRegenRateMultiplierWithWeapons.Value : BetterStaminaPlugin.staminaRegenRateMultiplier.Value); __instance.m_staminaRegenDelay = BetterStaminaPlugin.staminaRegenDelay.Value; if (BetterStaminaPlugin.enableStaminaRegenLogging != null && BetterStaminaPlugin.enableStaminaRegenLogging.Value) { CalculateNewStamina(__instance, ___m_wallRunning, ___m_staminaRegen, ___m_stamina, ___m_seman, ref ___m_staminaRegenTimer, dt); } } } internal static class DebugStaminaPatches { [HarmonyPatch(typeof(Player), "UseStamina")] [HarmonyPrefix] private static void UseStamina_Prefix(Player __instance, ref float __state, ref float ___m_stamina) { __state = ___m_stamina; } [HarmonyPatch(typeof(Player), "UseStamina")] [HarmonyPostfix] private static void UseStamina_Postfix(Player __instance, float __state, ref float ___m_stamina) { if (BetterStaminaPlugin.enableStaminaLogging != null && BetterStaminaPlugin.enableStaminaLogging.Value && ___m_stamina - __state != 0f) { BepInPluginTemplate.DebugLog($"UseStamina(): source - {new StackFrame(2).GetMethod().Name}; change - {___m_stamina - __state}"); } } } internal static class ToolsPatches { [HarmonyPatch(typeof(Player), "UseStamina")] [HarmonyPrefix] private static bool UseStamina_Prefix(Player __instance, ref float v) { if (((Humanoid)__instance).GetCurrentWeapon() != null) { string name = new StackFrame(2).GetMethod().Name; if ((name.Contains("Repair") || name.Contains("UpdatePlacement")) && BetterStaminaPlugin.removeToolStaminaCost.Value) { return false; } } return true; } } public class BepInPluginTemplate : BaseUnityPlugin { public enum LogMessageType { LogInfo, LogMessage, LogDebug, LogWarning, LogError, LogFatal } public static ConfigEntry<bool> enableLogging; public static ConfigEntry<bool> enableTranspilerLogging; protected BepInPlugin BepInAttr { get; set; } protected static Harmony harmonyInst { get; set; } protected static BepInPluginTemplate modInst { get; set; } protected static ManualLogSource Logger { get; set; } public static void DebugTranspilerLog(object message, LogMessageType msgType = LogMessageType.LogInfo) { DebugLog(message, msgType, transpilerlogs: true); } public static void DebugLog(object message, LogMessageType msgType = LogMessageType.LogInfo, bool transpilerlogs = false) { if (enableLogging != null && enableLogging.Value && (!transpilerlogs || enableTranspilerLogging == null || enableTranspilerLogging.Value)) { switch (msgType) { case LogMessageType.LogMessage: Logger.LogMessage(message); break; case LogMessageType.LogDebug: Logger.LogDebug(message); break; case LogMessageType.LogWarning: Logger.LogWarning(message); break; case LogMessageType.LogError: Logger.LogError(message); break; case LogMessageType.LogFatal: Logger.LogFatal(message); break; default: Logger.LogInfo(message); break; } } } public static void PrintOutInstructions(List<CodeInstruction> instructions) { DebugTranspilerLog(""); DebugTranspilerLog("#############################################################"); DebugTranspilerLog($"######## MODIFIED INSTRUCTIONS - {instructions.Count} ########"); DebugTranspilerLog("#############################################################"); DebugTranspilerLog(""); for (int i = 0; i < instructions.Count; i++) { CodeInstruction arg = instructions[i]; DebugTranspilerLog($"{i} {arg}"); } } protected virtual void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown modInst = this; BepInAttr = (BepInPlugin)Attribute.GetCustomAttribute(((object)this).GetType(), typeof(BepInPlugin)); Logger = Logger.CreateLogSource(BepInAttr.Name); harmonyInst = new Harmony(BepInAttr.GUID); DebugLog("Loading.."); } protected virtual void OnDestroy() { if (harmonyInst != null) { harmonyInst.UnpatchSelf(); } DebugLog("Unloading.."); Logger.Sources.Remove((ILogSource)(object)Logger); } } internal static class BepInExHelpers { public static ObjectDB FindObjectDB() { GameObject val = GameObject.Find("_GameMain"); if ((Object)(object)val != (Object)null) { ObjectDB component = val.GetComponent<ObjectDB>(); if ((Object)(object)component != (Object)null) { return component; } } return null; } } public static class MathUtils { public static string ColorRGBToHexString(int r, int g, int b) { return $"#{r:X2}{g:X2}{b:X2}"; } public static float ConvertRange(float originalStart, float originalEnd, float newStart, float newEnd, float value) { double num = (double)(newEnd - newStart) / (double)(originalEnd - originalStart); return (float)((double)newStart + (double)(value - originalStart) * num); } public static float Clamp(float value, float min, float max) { if (!(value < min)) { if (!(value > max)) { return value; } return max; } return min; } } public static class EasingFunctions { public enum Ease { EaseInQuad, EaseOutQuad, EaseInOutQuad, EaseInCubic, EaseOutCubic, EaseInOutCubic, EaseInQuart, EaseOutQuart, EaseInOutQuart, EaseInQuint, EaseOutQuint, EaseInOutQuint, EaseInSine, EaseOutSine, EaseInOutSine, EaseInExpo, EaseOutExpo, EaseInOutExpo, EaseInCirc, EaseOutCirc, EaseInOutCirc, Linear, Spring, EaseInBounce, EaseOutBounce, EaseInOutBounce, EaseInBack, EaseOutBack, EaseInOutBack, EaseInElastic, EaseOutElastic, EaseInOutElastic } public delegate float Function(float s, float e, float v); private const float NATURAL_LOG_OF_2 = 0.6931472f; public static float Linear(float start, float end, float value) { return Mathf.Lerp(start, end, value); } public static float Spring(float start, float end, float value) { value = Mathf.Clamp01(value); value = (Mathf.Sin(value * (float)Math.PI * (0.2f + 2.5f * value * value * value)) * Mathf.Pow(1f - value, 2.2f) + value) * (1f + 1.2f * (1f - value)); return start + (end - start) * value; } public static float EaseInQuad(float start, float end, float value) { end -= start; return end * value * value + start; } public static float EaseOutQuad(float start, float end, float value) { end -= start; return (0f - end) * value * (value - 2f) + start; } public static float EaseInOutQuad(float start, float end, float value) { value /= 0.5f; end -= start; if (value < 1f) { return end * 0.5f * value * value + start; } value -= 1f; return (0f - end) * 0.5f * (value * (value - 2f) - 1f) + start; } public static float EaseInCubic(float start, float end, float value) { end -= start; return end * value * value * value + start; } public static float EaseOutCubic(float start, float end, float value) { value -= 1f; end -= start; return end * (value * value * value + 1f) + start; } public static float EaseInOutCubic(float start, float end, float value) { value /= 0.5f; end -= start; if (value < 1f) { return end * 0.5f * value * value * value + start; } value -= 2f; return end * 0.5f * (value * value * value + 2f) + start; } public static float EaseInQuart(float start, float end, float value) { end -= start; return end * value * value * value * value + start; } public static float EaseOutQuart(float start, float end, float value) { value -= 1f; end -= start; return (0f - end) * (value * value * value * value - 1f) + start; } public static float EaseInOutQuart(float start, float end, float value) { value /= 0.5f; end -= start; if (value < 1f) { return end * 0.5f * value * value * value * value + start; } value -= 2f; return (0f - end) * 0.5f * (value * value * value * value - 2f) + start; } public static float EaseInQuint(float start, float end, float value) { end -= start; return end * value * value * value * value * value + start; } public static float EaseOutQuint(float start, float end, float value) { value -= 1f; end -= start; return end * (value * value * value * value * value + 1f) + start; } public static float EaseInOutQuint(float start, float end, float value) { value /= 0.5f; end -= start; if (value < 1f) { return end * 0.5f * value * value * value * value * value + start; } value -= 2f; return end * 0.5f * (value * value * value * value * value + 2f) + start; } public static float EaseInSine(float start, float end, float value) { end -= start; return (0f - end) * Mathf.Cos(value * ((float)Math.PI / 2f)) + end + start; } public static float EaseOutSine(float start, float end, float value) { end -= start; return end * Mathf.Sin(value * ((float)Math.PI / 2f)) + start; } public static float EaseInOutSine(float start, float end, float value) { end -= start; return (0f - end) * 0.5f * (Mathf.Cos((float)Math.PI * value) - 1f) + start; } public static float EaseInExpo(float start, float end, float value) { end -= start; return end * Mathf.Pow(2f, 10f * (value - 1f)) + start; } public static float EaseOutExpo(float start, float end, float value) { end -= start; return end * (0f - Mathf.Pow(2f, -10f * value) + 1f) + start; } public static float EaseInOutExpo(float start, float end, float value) { value /= 0.5f; end -= start; if (value < 1f) { return end * 0.5f * Mathf.Pow(2f, 10f * (value - 1f)) + start; } value -= 1f; return end * 0.5f * (0f - Mathf.Pow(2f, -10f * value) + 2f) + start; } public static float EaseInCirc(float start, float end, float value) { end -= start; return (0f - end) * (Mathf.Sqrt(1f - value * value) - 1f) + start; } public static float EaseOutCirc(float start, float end, float value) { value -= 1f; end -= start; return end * Mathf.Sqrt(1f - value * value) + start; } public static float EaseInOutCirc(float start, float end, float value) { value /= 0.5f; end -= start; if (value < 1f) { return (0f - end) * 0.5f * (Mathf.Sqrt(1f - value * value) - 1f) + start; } value -= 2f; return end * 0.5f * (Mathf.Sqrt(1f - value * value) + 1f) + start; } public static float EaseInBounce(float start, float end, float value) { end -= start; float num = 1f; return end - EaseOutBounce(0f, end, num - value) + start; } public static float EaseOutBounce(float start, float end, float value) { value /= 1f; end -= start; if (value < 0.36363637f) { return end * (7.5625f * value * value) + start; } if (value < 0.72727275f) { value -= 0.54545456f; return end * (7.5625f * value * value + 0.75f) + start; } if ((double)value < 0.9090909090909091) { value -= 0.8181818f; return end * (7.5625f * value * value + 0.9375f) + start; } value -= 21f / 22f; return end * (7.5625f * value * value + 63f / 64f) + start; } public static float EaseInOutBounce(float start, float end, float value) { end -= start; float num = 1f; if (value < num * 0.5f) { return EaseInBounce(0f, end, value * 2f) * 0.5f + start; } return EaseOutBounce(0f, end, value * 2f - num) * 0.5f + end * 0.5f + start; } public static float EaseInBack(float start, float end, float value) { end -= start; value /= 1f; float num = 1.70158f; return end * value * value * ((num + 1f) * value - num) + start; } public static float EaseOutBack(float start, float end, float value) { float num = 1.70158f; end -= start; value -= 1f; return end * (value * value * ((num + 1f) * value + num) + 1f) + start; } public static float EaseInOutBack(float start, float end, float value) { float num = 1.70158f; end -= start; value /= 0.5f; if (value < 1f) { num *= 1.525f; return end * 0.5f * (value * value * ((num + 1f) * value - num)) + start; } value -= 2f; num *= 1.525f; return end * 0.5f * (value * value * ((num + 1f) * value + num) + 2f) + start; } public static float EaseInElastic(float start, float end, float value) { end -= start; float num = 1f; float num2 = num * 0.3f; float num3 = 0f; if (value == 0f) { return start; } if ((value /= num) == 1f) { return start + end; } float num4; if (num3 == 0f || num3 < Mathf.Abs(end)) { num3 = end; num4 = num2 / 4f; } else { num4 = num2 / ((float)Math.PI * 2f) * Mathf.Asin(end / num3); } return 0f - num3 * Mathf.Pow(2f, 10f * (value -= 1f)) * Mathf.Sin((value * num - num4) * ((float)Math.PI * 2f) / num2) + start; } public static float EaseOutElastic(float start, float end, float value) { end -= start; float num = 1f; float num2 = num * 0.3f; float num3 = 0f; if (value == 0f) { return start; } if ((value /= num) == 1f) { return start + end; } float num4; if (num3 == 0f || num3 < Mathf.Abs(end)) { num3 = end; num4 = num2 * 0.25f; } else { num4 = num2 / ((float)Math.PI * 2f) * Mathf.Asin(end / num3); } return num3 * Mathf.Pow(2f, -10f * value) * Mathf.Sin((value * num - num4) * ((float)Math.PI * 2f) / num2) + end + start; } public static float EaseInOutElastic(float start, float end, float value) { end -= start; float num = 1f; float num2 = num * 0.3f; float num3 = 0f; if (value == 0f) { return start; } if ((value /= num * 0.5f) == 2f) { return start + end; } float num4; if (num3 == 0f || num3 < Mathf.Abs(end)) { num3 = end; num4 = num2 / 4f; } else { num4 = num2 / ((float)Math.PI * 2f) * Mathf.Asin(end / num3); } if (value < 1f) { return -0.5f * (num3 * Mathf.Pow(2f, 10f * (value -= 1f)) * Mathf.Sin((value * num - num4) * ((float)Math.PI * 2f) / num2)) + start; } return num3 * Mathf.Pow(2f, -10f * (value -= 1f)) * Mathf.Sin((value * num - num4) * ((float)Math.PI * 2f) / num2) * 0.5f + end + start; } public static Function GetEasingFunction(Ease easingFunction) { return easingFunction switch { Ease.EaseInQuad => EaseInQuad, Ease.EaseOutQuad => EaseOutQuad, Ease.EaseInOutQuad => EaseInOutQuad, Ease.EaseInCubic => EaseInCubic, Ease.EaseOutCubic => EaseOutCubic, Ease.EaseInOutCubic => EaseInOutCubic, Ease.EaseInQuart => EaseInQuart, Ease.EaseOutQuart => EaseOutQuart, Ease.EaseInOutQuart => EaseInOutQuart, Ease.EaseInQuint => EaseInQuint, Ease.EaseOutQuint => EaseOutQuint, Ease.EaseInOutQuint => EaseInOutQuint, Ease.EaseInSine => EaseInSine, Ease.EaseOutSine => EaseOutSine, Ease.EaseInOutSine => EaseInOutSine, Ease.EaseInExpo => EaseInExpo, Ease.EaseOutExpo => EaseOutExpo, Ease.EaseInOutExpo => EaseInOutExpo, Ease.EaseInCirc => EaseInCirc, Ease.EaseOutCirc => EaseOutCirc, Ease.EaseInOutCirc => EaseInOutCirc, Ease.Linear => Linear, Ease.Spring => Spring, Ease.EaseInBounce => EaseInBounce, Ease.EaseOutBounce => EaseOutBounce, Ease.EaseInOutBounce => EaseInOutBounce, Ease.EaseInBack => EaseInBack, Ease.EaseOutBack => EaseOutBack, Ease.EaseInOutBack => EaseInOutBack, Ease.EaseInElastic => EaseInElastic, Ease.EaseOutElastic => EaseOutElastic, Ease.EaseInOutElastic => EaseInOutElastic, _ => null, }; } } namespace BetterStamina; [BepInPlugin("bakaSpaceman.BetterStamina", "Better Stamina - Hildirs Request Update", "2.1.0")] public class BetterStaminaPlugin : BepInPluginTemplate { public static ConfigEntry<bool> enableStaminaLogging; public static ConfigEntry<bool> enableStaminaRegenLogging; public static ConfigEntry<bool> enableSkillStaminaLogging; public static ConfigEntry<int> nexusID; public static ConfigEntry<bool> removeEncumberedStaminaDrain; public static ConfigEntry<float> staminaRegenRateMultiplier; public static ConfigEntry<float> staminaRegenRateMultiplierWithWeapons; public static ConfigEntry<float> staminaRegenDelay; public static ConfigEntry<bool> removeToolStaminaCost; public static ConfigEntry<float> runMaxSkillStaminaCost; public static ConfigEntry<float> runWithWeapMaxSkillStaminaCost; public static ConfigEntry<float> dodgeMaxSkillStaminaCost; public static ConfigEntry<float> jumpMaxSkillStaminaCost; public static ConfigEntry<float> blockMaxSkillStaminaCost; public static ConfigEntry<float> sneakMaxSkillStaminaCost; public static ConfigEntry<float> weaponMaxSkillAttackStaminaCost; public static ConfigEntry<float> bowMaxSkillHoldStaminaCost; public static ConfigEntry<float> swimMaxStaminaCost; public static ConfigEntry<float> swimMinStaminaCost; public static ConfigEntry<float> restedStaminaRegenMultiplier; public static ConfigEntry<float> restedDurationPerComfortLvl; public static ConfigEntry<float> wetStaminaRegenMultiplier; public static ConfigEntry<float> coldStaminaRegenMultiplier; public static FieldInfo playerSkillsField = typeof(Player).GetField("m_skills", BindingFlags.Instance | BindingFlags.NonPublic); public static FieldInfo statusEffectsField = typeof(SEMan).GetField("m_statusEffects", BindingFlags.Instance | BindingFlags.NonPublic); private void SetupConfig() { nexusID = ((BaseUnityPlugin)this).Config.Bind<int>("General", "NexusID", 153, "Nexus mod ID for updates"); staminaRegenRateMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("General", "StaminaRegenRateMod", 1.5f, "1 - Default rate, 1.5 - 50% faster rate, 0.5 - 50% slower, etc."); staminaRegenRateMultiplierWithWeapons = ((BaseUnityPlugin)this).Config.Bind<float>("General", "StaminaRegenRateModWithWeapons", 1.4f, "This will be used instead of StaminaRegenRateMod if player has weapons equipped. 1 - Default rate, 1.5 - 50% faster rate, 0.5 - 50% slower, etc."); staminaRegenDelay = ((BaseUnityPlugin)this).Config.Bind<float>("General", "StaminaRegenDelay", 1f, "Time in seconds before stamina starts regenerating. Default value - 1."); removeEncumberedStaminaDrain = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RemoveEncumberedStaminaDrain", true, "Prevents stamina drain while encumbered."); removeToolStaminaCost = ((BaseUnityPlugin)this).Config.Bind<bool>("Tools", "RemoveToolStaminaCost", true, "Using tools to repair/build will not consume stamina."); runMaxSkillStaminaCost = ((BaseUnityPlugin)this).Config.Bind<float>("Skills", "RunCostAtMaxSkill", 0.4f, "The value is a percentage modifier of the default cost. 1 - default cost, < 1 - reduced cost, > 1 - increased"); runWithWeapMaxSkillStaminaCost = ((BaseUnityPlugin)this).Config.Bind<float>("Skills", "RunWithWeaponsCostAtMaxSkill", 0.5f, "This will be used instead of RunCostModifierAtMaxSkill if player has weapons equipped. The value is a percentage modifier of the default cost. 1 - default cost, < 1 - reduced cost, > 1 - increased"); dodgeMaxSkillStaminaCost = ((BaseUnityPlugin)this).Config.Bind<float>("Skills", "DodgeCostAtMaxSkill", 0.67f, "The value is a percentage modifier of the default cost. 1 - default cost, < 1 - reduced cost, > 1 - increased"); jumpMaxSkillStaminaCost = ((BaseUnityPlugin)this).Config.Bind<float>("Skills", "JumpCostAtMaxSkill", 0.67f, "The value is a percentage modifier of the default cost. 1 - default cost, < 1 - reduced cost, > 1 - increased"); blockMaxSkillStaminaCost = ((BaseUnityPlugin)this).Config.Bind<float>("Skills", "BlockCostAtMaxSkill", 0.67f, "The value is a percentage modifier of the default cost. 1 - default cost, < 1 - reduced cost, > 1 - increased"); sneakMaxSkillStaminaCost = ((BaseUnityPlugin)this).Config.Bind<float>("Skills", "SneakCostAtMaxSkill", 0.67f, "The value is a percentage modifier of the default cost. 1 - default cost, < 1 - reduced cost, > 1 - increased"); weaponMaxSkillAttackStaminaCost = ((BaseUnityPlugin)this).Config.Bind<float>("Skills", "WeaponAttackCostAtMaxSkill", 0.67f, "The value is a percentage modifier of the default cost. 1 - default cost, < 1 - reduced cost, > 1 - increased"); bowMaxSkillHoldStaminaCost = ((BaseUnityPlugin)this).Config.Bind<float>("Skills", "HoldBowCostAtMaxSkill", 0.67f, "The value is a percentage modifier of the default cost. 1 - default cost, < 1 - reduced cost, > 1 - increased"); swimMaxStaminaCost = ((BaseUnityPlugin)this).Config.Bind<float>("Skills", "SwimCostAtMinSkill", 6f, "Swimming stamina cost defined in units at minimum Swim skill."); swimMinStaminaCost = ((BaseUnityPlugin)this).Config.Bind<float>("Skills", "SwimCostAtMaxSkill", 3f, "Swimming stamina cost defined in units at maximum Swim skill."); coldStaminaRegenMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Status Effects", "ColdStaminaRegenModifier", 0.75f, "Vanilla value - 0.75 (25% penalty)"); restedStaminaRegenMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Status Effects", "RestedStaminaRegenModifier", 1.5f, "Vanilla value - 2 (100% bonus)"); restedDurationPerComfortLvl = ((BaseUnityPlugin)this).Config.Bind<float>("Status Effects", "RestedDurationIncreasePerConfortLevel", 60f, "This amount of seconds will be added to the effects duration per comfort level. Vanilla value - 60 seconds"); wetStaminaRegenMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Status Effects", "WetStaminaRegenModifier", 0.85f, "Vanilla value - 0.85 (15% penalty)"); } protected override void Awake() { base.Awake(); SetupConfig(); if (BepInPluginTemplate.enableLogging != null && BepInPluginTemplate.enableLogging.Value) { BepInPluginTemplate.harmonyInst.PatchAll(typeof(DebugStaminaPatches)); } BepInPluginTemplate.harmonyInst.PatchAll(typeof(GeneralStaminaPatches)); BepInPluginTemplate.harmonyInst.PatchAll(typeof(ToolsPatches)); BepInPluginTemplate.harmonyInst.PatchAll(typeof(SkillPatches)); BepInPluginTemplate.harmonyInst.PatchAll(typeof(StatusEffectPatches)); } }