using System; using System.Diagnostics; 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 UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("youxia173")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.11.0")] [assembly: AssemblyInformationalVersion("1.0.11")] [assembly: AssemblyProduct("StaminaCostTweaks")] [assembly: AssemblyTitle("youxia173.StaminaCostTweaks")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.11.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 StaminaCostTweaks { [HarmonyPatch(typeof(Character), "UseStamina")] internal static class Character_UseStamina_Patch { [HarmonyPrefix] private static bool Prefix(Character __instance, ref float usage, ref bool __result) { if (usage == 0f || (Object)(object)__instance == (Object)null) { return true; } if (Plugin.FreeStaminaEnabled && __instance.IsLocal) { __result = true; return false; } if (IsExtremeClimbActive(__instance) && IsClimbRelatedSpend(__instance)) { float num = Plugin.PercentToMultiplier(Plugin.ExtremeClimbCostPercent.Value); if (!Mathf.Approximately(num, 1f)) { usage *= num; } return true; } if (!TryGetManagedMultiplier(__instance, out var mult)) { return true; } if (Mathf.Approximately(mult, 1f)) { return true; } usage *= mult; return true; } private static bool IsExtremeClimbActive(Character character) { if (!Plugin.ExtremeClimbEnabled.Value || (Object)(object)character == (Object)null || !character.IsLocal) { return false; } CharacterData data = character.data; if ((Object)(object)data == (Object)null) { return false; } float num = Mathf.Clamp(Plugin.ExtremeClimbBelowPercent.Value, 1f, 100f) / 100f; bool num2 = data.extraStamina <= 0.001f && data.currentStamina < num; bool flag = data.currentStamina <= 0.001f && data.extraStamina < num; return num2 || flag; } private static bool IsClimbRelatedSpend(Character character) { if (StaminaCostContext.Kind == StaminaCostKind.ClimbJump || StaminaCostContext.Kind == StaminaCostKind.VineIdle || StaminaCostContext.Kind == StaminaCostKind.Glider) { return true; } CharacterData data = character.data; if ((Object)(object)data == (Object)null) { return false; } if (!data.isClimbing && !data.isVineClimbing) { return data.isRopeClimbing; } return true; } private static bool TryGetManagedMultiplier(Character character, out float mult) { mult = 1f; if (StaminaCostContext.Kind == StaminaCostKind.ClimbJump) { mult = Plugin.PercentToMultiplier(Plugin.ClimbJumpCostPercent.Value); return true; } if (StaminaCostContext.Kind == StaminaCostKind.VineIdle) { mult = Plugin.PercentToMultiplier(Plugin.VineIdleCostPercent.Value); return true; } if (StaminaCostContext.Kind == StaminaCostKind.Glider) { mult = Plugin.PercentToMultiplier(Plugin.GliderCostPercent.Value); return true; } CharacterData data = character.data; if ((Object)(object)data == (Object)null) { return false; } if (data.isVineClimbing) { if (Mathf.Abs(character.input.movementInput.y) < 0.01f) { mult = Plugin.PercentToMultiplier(Plugin.VineIdleCostPercent.Value); return true; } return false; } if (data.isClimbing) { mult = Plugin.PercentToMultiplier(Plugin.ClimbCostPercent.Value); return true; } if (data.isSprinting) { mult = Plugin.PercentToMultiplier(Plugin.SprintCostPercent.Value); return true; } return false; } } [HarmonyPatch(typeof(CharacterClimbing), "RPCA_ClimbJump")] internal static class CharacterClimbing_ClimbJump_Patch { [HarmonyPrefix] private static void Prefix() { StaminaCostContext.Kind = StaminaCostKind.ClimbJump; } [HarmonyFinalizer] private static void Finalizer() { StaminaCostContext.Kind = StaminaCostKind.None; } } [HarmonyPatch(typeof(CharacterVineClimbing), "Update")] internal static class CharacterVineClimbing_Update_Patch { [HarmonyPrefix] private static void Prefix(CharacterVineClimbing __instance) { object? obj = AccessTools.Field(typeof(CharacterVineClimbing), "character")?.GetValue(__instance); Character val = (Character)((obj is Character) ? obj : null); if (!((Object)(object)val == (Object)null) && val.IsLocal && val.data.isVineClimbing && (__instance.Sliding() || Mathf.Abs(val.input.movementInput.y) < 0.01f)) { StaminaCostContext.Kind = StaminaCostKind.VineIdle; } } [HarmonyFinalizer] private static void Finalizer() { if (StaminaCostContext.Kind == StaminaCostKind.VineIdle) { StaminaCostContext.Kind = StaminaCostKind.None; } } } [HarmonyPatch(typeof(Glider), "FixedUpdate")] internal static class Glider_FixedUpdate_Patch { [HarmonyPrefix] private static void Prefix() { StaminaCostContext.Kind = StaminaCostKind.Glider; } [HarmonyFinalizer] private static void Finalizer() { if (StaminaCostContext.Kind == StaminaCostKind.Glider) { StaminaCostContext.Kind = StaminaCostKind.None; } } } [HarmonyPatch(typeof(Character), "UpdateVariablesFixed")] internal static class Character_UpdateVariablesFixed_Patch { [HarmonyPrefix] private static void Prefix() { StaminaCostContext.Kind = StaminaCostKind.NaturalRegen; } [HarmonyFinalizer] private static void Finalizer() { if (StaminaCostContext.Kind == StaminaCostKind.NaturalRegen) { StaminaCostContext.Kind = StaminaCostKind.None; } } } [HarmonyPatch(typeof(Character), "AddStamina")] internal static class Character_AddStamina_Patch { [HarmonyPrefix] private static bool Prefix(ref float add) { if (StaminaCostContext.Kind != StaminaCostKind.NaturalRegen) { return true; } if (add <= 0f) { return true; } float num = Plugin.PercentToMultiplier(Plugin.StaminaRegenPercent.Value); if (num <= 0f) { return false; } if (Mathf.Approximately(num, 1f)) { return true; } add *= num; return add > 0f; } } [HarmonyPatch(typeof(Character), "CanRegenStamina")] internal static class Character_CanRegenStamina_Patch { [HarmonyPrefix] private static bool Prefix(Character __instance, ref bool __result) { float num = Plugin.PercentToMultiplier(Plugin.StaminaRegenDelayPercent.Value); if (Mathf.Approximately(num, 1f)) { return true; } CharacterData data = __instance.data; if ((Object)(object)data == (Object)null) { return true; } if (Object.op_Implicit((Object)(object)data.currentClimbHandle)) { __result = true; return false; } if (__instance.IsStuck()) { __result = true; return false; } float num2 = ((data.currentStamina > 0f) ? 1f : 2f) * num; if ((data.sinceGrounded > 0.2f && ((Object)(object)__instance.refs?.afflictions == (Object)null || !__instance.refs.afflictions.isWebbed)) || data.sinceUseStamina < num2) { __result = false; return false; } __result = true; return false; } } [BepInPlugin("youxia173.StaminaCostTweaks", "StaminaCostTweaks", "1.0.11")] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Log; public static ConfigEntry SprintCostPercent; public static ConfigEntry ClimbCostPercent; public static ConfigEntry ClimbJumpCostPercent; public static ConfigEntry VineIdleCostPercent; public static ConfigEntry GliderCostPercent; public static ConfigEntry StaminaRegenPercent; public static ConfigEntry StaminaRegenDelayPercent; public static ConfigEntry ExtremeClimbEnabled; public static ConfigEntry ExtremeClimbCostPercent; public static ConfigEntry ExtremeClimbBelowPercent; public static ConfigEntry ToggleFreeStaminaKey; private Harmony? _harmony; private float _toastUntil; private string _toastText = ""; public static bool FreeStaminaEnabled { get; private set; } private void Awake() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Expected O, but got Unknown //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Expected O, but got Unknown //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Expected O, but got Unknown //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Expected O, but got Unknown //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Expected O, but got Unknown //IL_0391: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; SprintCostPercent = ((BaseUnityPlugin)this).Config.Bind("StaminaCost", "SprintCostPercent", 80f, new ConfigDescription("冲刺体力消耗百分比。 / Sprint stamina cost percent. 消耗百分比:100 = 原版,80 = 原版的 80%。在难度系数之后生效。范围 0–500。仅在「免费体力」关闭时生效。 / Cost percent: 100 = vanilla, 80 = 80% of vanilla. Applied after difficulty multipliers. Range 0-500. Only when free stamina is OFF.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 500f), Array.Empty())); ClimbCostPercent = ((BaseUnityPlugin)this).Config.Bind("StaminaCost", "ClimbCostPercent", 80f, new ConfigDescription("攀爬(持续)体力消耗百分比。 / Climb (continuous) stamina cost percent. 消耗百分比:100 = 原版,80 = 原版的 80%。在难度系数之后生效。范围 0–500。仅在「免费体力」关闭时生效。 / Cost percent: 100 = vanilla, 80 = 80% of vanilla. Applied after difficulty multipliers. Range 0-500. Only when free stamina is OFF.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 500f), Array.Empty())); ClimbJumpCostPercent = ((BaseUnityPlugin)this).Config.Bind("StaminaCost", "ClimbJumpCostPercent", 80f, new ConfigDescription("攀爬跳跃体力消耗百分比。 / Climb-jump stamina cost percent. 消耗百分比:100 = 原版,80 = 原版的 80%。在难度系数之后生效。范围 0–500。仅在「免费体力」关闭时生效。 / Cost percent: 100 = vanilla, 80 = 80% of vanilla. Applied after difficulty multipliers. Range 0-500. Only when free stamina is OFF.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 500f), Array.Empty())); VineIdleCostPercent = ((BaseUnityPlugin)this).Config.Bind("StaminaCost", "VineIdleCostPercent", 80f, new ConfigDescription("藤蔓空闲(几乎不动)体力消耗百分比。 / Vine idle stamina cost percent. 消耗百分比:100 = 原版,80 = 原版的 80%。在难度系数之后生效。范围 0–500。仅在「免费体力」关闭时生效。 / Cost percent: 100 = vanilla, 80 = 80% of vanilla. Applied after difficulty multipliers. Range 0-500. Only when free stamina is OFF.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 500f), Array.Empty())); GliderCostPercent = ((BaseUnityPlugin)this).Config.Bind("StaminaCost", "GliderCostPercent", 80f, new ConfigDescription("滑翔伞体力消耗百分比(开伞+持续)。 / Glider stamina cost percent (open + continuous). 消耗百分比:100 = 原版,80 = 原版的 80%。在难度系数之后生效。范围 0–500。仅在「免费体力」关闭时生效。 / Cost percent: 100 = vanilla, 80 = 80% of vanilla. Applied after difficulty multipliers. Range 0-500. Only when free stamina is OFF.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 500f), Array.Empty())); StaminaRegenPercent = ((BaseUnityPlugin)this).Config.Bind("StaminaCost", "StaminaRegenPercent", 120f, new ConfigDescription("自然体力恢复速度百分比(原版约每秒 0.2)。100 = 原版,120 = 快 20%,200 = 两倍,0 = 不自然回体。不影响食物/士气等额外回体。范围 0–500。 / Natural stamina regen percent (vanilla ~0.2/s). 100 = vanilla, 120 = +20%, 200 = 2x, 0 = no natural regen. Does not affect food/morale bonus stamina. Range 0-500.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 500f), Array.Empty())); StaminaRegenDelayPercent = ((BaseUnityPlugin)this).Config.Bind("StaminaCost", "StaminaRegenDelayPercent", 50f, new ConfigDescription("耗体后开始自然回体的等待时间百分比。原版:有体力约 1 秒,空条约 2 秒。100 = 原版,50 = 延迟减半(有体力 0.5 秒 / 空条 1 秒),0 = 几乎立刻开始回。范围 0–500。 / Delay before natural regen after spending stamina. Vanilla: ~1s if stamina>0, ~2s if empty. 100 = vanilla, 50 = half delay, 0 = near-instant. Range 0-500.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 500f), Array.Empty())); ExtremeClimbEnabled = ((BaseUnityPlugin)this).Config.Bind("StaminaCost", "ExtremeClimbEnabled", true, "极限攀爬:满足任一条件时,攀爬/藤蔓/绳/滑翔伞消耗改为「极限攀爬消耗百分比」——①额外体力≈0 且当前体力低于阈值;②当前体力≈0 且额外体力低于阈值。 / Extreme climb when (bonus≈0 & current below threshold) OR (current≈0 & bonus below threshold)."); ExtremeClimbCostPercent = ((BaseUnityPlugin)this).Config.Bind("StaminaCost", "ExtremeClimbCostPercent", 30f, new ConfigDescription("极限状态下的消耗百分比(相对原版)。默认 30 = 正常的 30%。覆盖攀爬/攀爬跳/藤蔓/滑翔伞等配置。范围 0–500。 / Cost percent in extreme state (vs vanilla). Default 30. Overrides climb/vine/glider percents. Range 0-500.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 500f), Array.Empty())); ExtremeClimbBelowPercent = ((BaseUnityPlugin)this).Config.Bind("StaminaCost", "ExtremeClimbBelowPercent", 10f, new ConfigDescription("极限攀爬阈值(百分比)。用于:当前体力 < 此值(额外体力为 0 时),或额外体力 < 此值(当前体力为 0 时)。默认 10。范围 1–100。 / Threshold % for extreme climb: current < N when bonus=0, or bonus < N when current=0. Default 10. Range 1-100.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); ToggleFreeStaminaKey = ((BaseUnityPlugin)this).Config.Bind("Hotkeys", "ToggleFreeStaminaKey", (KeyCode)54, "切换免费体力(本机所有 UseStamina 归零)。默认大键盘 6(Alpha6);小键盘用 Keypad6。 / Toggle free stamina (skip all local UseStamina). Default Alpha6 (top-row 6). Use Keypad6 for numpad."); FreeStaminaEnabled = false; _harmony = new Harmony("youxia173.StaminaCostTweaks"); _harmony.PatchAll(); Log.LogInfo((object)("StaminaCostTweaks v1.0.11 by youxia173 loaded. " + $"Sprint={SprintCostPercent.Value}% Climb={ClimbCostPercent.Value}% " + $"ClimbJump={ClimbJumpCostPercent.Value}% VineIdle={VineIdleCostPercent.Value}% " + $"Glider={GliderCostPercent.Value}% Regen={StaminaRegenPercent.Value}% " + $"RegenDelay={StaminaRegenDelayPercent.Value}% " + string.Format("ExtremeClimb={0}@{1}%/<{2}% ", ExtremeClimbEnabled.Value ? "ON" : "OFF", ExtremeClimbCostPercent.Value, ExtremeClimbBelowPercent.Value) + $"ToggleKey={ToggleFreeStaminaKey.Value} FreeStamina=OFF")); } private void Update() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) KeyCode value = ToggleFreeStaminaKey.Value; if ((int)value != 0 && Input.GetKeyDown(value)) { FreeStaminaEnabled = !FreeStaminaEnabled; _toastText = (FreeStaminaEnabled ? "免费体力 ON / Free stamina ON" : "免费体力 OFF / Free stamina OFF"); _toastUntil = Time.unscaledTime + 2.5f; Log.LogInfo((object)(FreeStaminaEnabled ? "Free stamina ON (all local UseStamina skipped)" : "Free stamina OFF (config percents apply)")); } } private void OnGUI() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) if (!(Time.unscaledTime > _toastUntil) && !string.IsNullOrEmpty(_toastText)) { GUIStyle val = new GUIStyle(GUI.skin.box) { fontSize = 20, alignment = (TextAnchor)4, fontStyle = (FontStyle)1 }; val.normal.textColor = Color.white; float num = 360f; float num2 = 48f; GUI.Box(new Rect(((float)Screen.width - num) * 0.5f, (float)Screen.height * 0.18f, num, num2), _toastText, val); } } private void OnDestroy() { Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } public static float PercentToMultiplier(float percent) { if (percent < 0f) { percent = 0f; } return percent / 100f; } } internal enum StaminaCostKind { None, ClimbJump, VineIdle, Glider, NaturalRegen } internal static class StaminaCostContext { [ThreadStatic] private static StaminaCostKind _kind; public static StaminaCostKind Kind { get { return _kind; } set { _kind = value; } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "youxia173.StaminaCostTweaks"; public const string PLUGIN_NAME = "StaminaCostTweaks"; public const string PLUGIN_VERSION = "1.0.11"; } }